aozhiwei 28bca7b91c 1
2021-08-25 13:48:35 +08:00

499 lines
14 KiB
C++

#include "precompile.h"
#include <math.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"
#include "explosion.h"
#include "obstacle.h"
#include "ability.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();
}
RecalcSelfCollider();
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();
SetDef(hero_meta_->i->def());
SetHP(hero_meta_->i->health());
SetMaxHP(std::max(GetHP(), GetMaxHP()));
TryAddBuff(this, meta->car_deactive_buff_id);
cur_oil_ = meta->i->max_oil();
}
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(GetUniId());
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(GetUniId());
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_->GetUniId() : 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());
p->set_oil(cur_oil_);
p->set_max_oil(meta->i->max_oil());
p->set_bullet_num(weapons[GUN_SLOT1].ammo);
p->set_seat_num(meta->int_param2);
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->GetWeakPtrRef());
if (passengers_.empty()) {
team_id = 0;
room->TakeOffCarObject(GetUniId(), 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;
driver_->SetAttackDir(a8::Vec2::RIGHT);
SetAttackDir(driver_->GetAttackDir());
room->TakeOnCarObject(GetUniId());
}
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->GetWeakPtrRef());
if (passengers_.size() == 1) {
RemoveBuffByEffectId(kBET_CarDeactive);
TryAddBuff(this, meta->car_active_buff_id);
}
SyncAroundPlayers(__FILE__, __LINE__, __func__);
room->NotifyUiUpdate();
}
void Car::SwitchSeat(Human* passenger, int seat)
{
if (later_removed_) {
return;
}
if (seat < 0 || seat >= meta->int_param2) {
return;
}
if (!IsPassenger(passenger)) {
return;
}
if (GetPassengerBySeat(seat)) {
return;
}
if (seat == 0) {
passenger->RemoveBuffByEffectId(kBET_Passenger);
passenger->SetSeat(seat);
driver_ = passenger;
passenger->MustBeAddBuff(passenger, DRIVER_BUFFID);
room->frame_event.AddCarChg(passenger->GetWeakPtrRef());
SyncAroundPlayers(__FILE__, __LINE__, __func__);
} else {
passenger->SetSeat(seat);
if (driver_ == passenger) {
driver_ = nullptr;
passenger->RemoveBuffByEffectId(kBET_Driver);
passenger->MustBeAddBuff(passenger, PASSENGER_BUFFID);
} else {
Buff* buff = passenger->GetBuffByEffectId(kBET_Passenger);
buff->CalcPassengerShotOffset();
passenger->need_sync_active_player = true;
}
room->frame_event.AddCarChg(passenger->GetWeakPtrRef());
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();
speed *= 1 + GetAbility()->GetAttrRate(kHAT_Speed);
return speed;
}
void Car::OnBulletHit(Bullet* bullet)
{
if (!IsDead(room)) {
float dmg = bullet->GetAtk() + bullet->gun_meta->i->atk_mech();
float def = GetDef() * (1 + GetAbility()->GetAttrRate(kHAT_Def)) +
GetAbility()->GetAttrAbs(kHAT_Def);
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
finaly_dmg = std::max(finaly_dmg, 0.0f);
if (bullet->meta->buff_meta) {
MustBeAddBuff(bullet->sender.Get(), bullet->meta->i->buffid());
}
if (!bullet->IsPreBattleBullet()) {
DecHP(finaly_dmg,
bullet->sender.Get()->GetUniId(),
bullet->sender.Get()->GetName(),
bullet->gun_meta->i->id());
}
if (bullet->meta->buff_meta) {
MustBeAddBuff(this, bullet->meta->i->buffid());
}
}
}
void Car::OnExplosionHit(Explosion* e)
{
if (IsInvincible()) {
return;
}
if (dead) {
return;
}
if (e->IsPreBattleExplosion()) {
return;
}
if (HasBuffEffect(kBET_Jump) ||
HasBuffEffect(kBET_Fly)) {
return;
}
float dmg = e->GetDmg();
float def = GetDef() * (1 + GetAbility()->GetAttrRate(kHAT_Def)) +
GetAbility()->GetAttrAbs(kHAT_Def);
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
finaly_dmg = std::max(finaly_dmg, 0.0f);
#ifdef DEBUG
{
room->BroadcastDebugMsg(a8::Format("explosion dmg:%d def:%d finaly_dmg:%d",
{dmg,
def,
finaly_dmg}));
}
#endif
#if 1
DecHP(finaly_dmg,
1,
"",
1);
#else
DecHP(finaly_dmg,
sender.Get()->GetUniId(),
sender.Get()->GetName(),
gun_meta->i->id());
#endif
}
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);
SetHP(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;
room->TakeOnCarObject(GetUniId());
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->GetWeakPtrRef());
}
Explosion explosion;
explosion.IndifferenceAttack(
room,
GetPos(),
meta->i->explosion_range(),
meta->i->explosion_effect(),
meta->i->atk()
);
room->NotifyUiUpdate();
}
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::GetHitAabbBox(AabbCollider& aabb_box)
{
aabb_box.active = true;
aabb_box.owner = this;
aabb_box._min.x = -hero_meta_->i->hit_radius();
aabb_box._min.y = -hero_meta_->i->hit_radius();
aabb_box._max.x = hero_meta_->i->hit_radius();
aabb_box._max.y = hero_meta_->i->hit_radius();
aabb_box.MoveCenter(hero_meta_->i->hit_offset_x(), hero_meta_->i->hit_offset_y());
}
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();
}
void Car::SetAttackDir(const a8::Vec2& attack_dir)
{
Creature::SetAttackDir(attack_dir);
}
void Car::DecOil(float dec_oil)
{
dec_oil *= 1 - GetAbility()->GetAttrRate(kHAT_CarOil);
cur_oil_ -= dec_oil;
cur_oil_ = std::max(0.0f, cur_oil_);
if (!HasOil()) {
if (driver_) {
driver_->SetAttackDir(a8::Vec2::RIGHT);
}
SetAttackDir(a8::Vec2::RIGHT);
}
}
float Car::GetMaxOil()
{
return meta->i->max_oil();
}
void Car::DropItems(Obstacle* obstacle)
{
if (obstacle->meta->i->drop() != 0) {
room->ScatterDrop(obstacle->GetPos(), obstacle->meta->i->drop());
}
}
void Car::RecalcSelfCollider()
{
if (!self_collider_) {
self_collider_ = new CircleCollider();
self_collider_->owner = this;
AddEntityCollider(self_collider_);
}
self_collider_->pos = a8::Vec2(hero_meta_->i->move_offset_x(), hero_meta_->i->move_offset_y());
self_collider_->rad = hero_meta_->i->radius();
}
bool Car::NeedCreatureCollision()
{
return false;
}
void Car::CheckCreatureCollision()
{
}