aozhiwei b41a83eea2 1
2024-01-19 17:47:33 +08:00

567 lines
22 KiB
C++

#include "precompile.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/vec2.hpp>
#include "shot.h"
#include "creature.h"
#include "room.h"
#include "car.h"
#include "trigger.h"
#include "buff.h"
#include "debugcmd.h"
#include "ability.h"
#include "netdata.h"
#include "mt/Param.h"
#include "mt/Hero.h"
#include "mt/Equip.h"
#include "mt/Buff.h"
#include "mt/Skill.h"
#include "mt/SkillNumber.h"
static const auto hero_transform =
glm::rotate(
glm::mat4(1.0),
//glm::radians(65.0f),
glm::radians(0.0f),
glm::vec3(0.0, 0.0, 1.0)
);
struct BulletInfo
{
CreatureWeakPtr c;
long long weapon_uniid = 0;
const mt::Equip* weapon_meta = nullptr;
const mt::Equip* bullet_meta = nullptr;
const mt::Skill* skill_meta = nullptr;
Position bullet_born_pos;
glm::vec3 bullet_dir = GlmHelper::ZERO;
float fly_distance = 0;
int weapon_lv = 0;
int weapon_buff_id = 0;
int delay_time = 0;
float recoil_force = 0;
int invincible_buff_uniid = 0;
int trace_target_uniid = 0;
float track_change_time = 0;
int is_through = 0;
int hand = 0;
float shot_animi_time = 0;
const mt::HeroShotAnimation* shot_animi = nullptr;
int bullet_idx = 0;
int bullet_num = 0;
std::shared_ptr<std::set<int>> reporter_list;
int shot_uniid = 0;
a8::XTimerWp keep_shot_animi_timer_ptr;
};
static void CalcGunMuzzlePosition(Creature* c,
int weapon_lv,
const mt::Equip* weapon_meta,
const mt::HeroShotAnimation* shot_animi,
glm::vec4& gun_muzzle_position,
int bulletIdx,
int bulletNum)
{
bool is_player = c->IsPlayer();
if (c->GetHeroMeta()->id() == 60100) {
int i = 0;
}
if (shot_animi) {
if (weapon_meta->double_gun()&&
bulletIdx > (int)(bulletNum / 2)) {
gun_muzzle_position +=
glm::vec4(
shot_animi->l_x,
shot_animi->l_y,
shot_animi->l_z,
0
);
} else {
if (c->IsCar() && !weapon_meta->double_gun()) {
switch (c->shot_hole) {
case 1:
{
gun_muzzle_position +=
glm::vec4(
shot_animi->p3_x,
shot_animi->p3_y,
shot_animi->p3_z,
0
);
}
break;
case 2:
{
gun_muzzle_position +=
glm::vec4(
shot_animi->p4_x,
shot_animi->p4_y,
shot_animi->p4_z,
0
);
}
break;
case 3:
{
gun_muzzle_position +=
glm::vec4(
shot_animi->p5_x,
shot_animi->p5_y,
shot_animi->p5_z,
0
);
}
break;
default:
{
}
break;
}
} else {
if (c->GetHeroMeta()->id() == 60100) {
gun_muzzle_position +=
glm::vec4(
shot_animi->p3_x,
shot_animi->p3_y,
shot_animi->p3_z,
0
);
} else {
gun_muzzle_position +=
glm::vec4(
shot_animi->r_x,
shot_animi->r_y,
shot_animi->r_z,
0
);
}
}
}
}//end if
if (weapon_lv > 0 && weapon_lv < weapon_meta->_gun_muzzle_positions.size() + 1) {
auto pos = weapon_meta->_gun_muzzle_positions.at(weapon_lv - 1);
gun_muzzle_position +=
glm::vec4(
std::get<0>(*pos.get()),
std::get<1>(*pos.get()),
std::get<2>(*pos.get()),
0
);
}
}
static void InternalCreateBullet(BulletInfo& bullet_info)
{
if (!bullet_info.c.Get()) {
return;
}
Creature* c = bullet_info.c.Get();
if (c->dead) {
return;
}
if (c->downed) {
return;
}
#ifdef MYDEBUG
if (bullet_info.weapon_meta->id() == 60111) {
a8::XPrintf("create bullet %d %d\n",
{
bullet_info.bullet_idx,
bullet_info.delay_time
});
}
#endif
if (bullet_info.delay_time <= 0) {
if (c->GetCurrWeapon()->meta->bullet_consume_type() == kBulletConsumeMulti) {
if (c->GetCurrWeapon()->ammo <= 0) {
return;
}
--c->GetCurrWeapon()->ammo;
if (c->GetCurrWeapon()->ammo <= 0) {
c->AutoLoadingBullet();
}
if ((c->IsPlayer() || c->IsCar())) {
c->room->frame_event.AddBulletNumChg(c->GetWeakPtrRef());
c->room->frame_event.AddWeaponAmmoChg(c->GetWeakPtrRef());
}
}
if (bullet_info.recoil_force > 0) {
if (c->GetCurrWeapon()->ammo <= 0) {
c->DoRecoilForce(bullet_info.recoil_force);
bullet_info.bullet_born_pos.FromGlmVec3(bullet_info.bullet_born_pos.ToGlmVec3() -
(bullet_info.bullet_dir * bullet_info.recoil_force));
}
}
if (c->IsCar() && c->AsCar()->IsSingle()) {
// 999
glm::vec3 bullet_born_offset = glm::vec3(0.0f, 0.0f, 0.0f);
bool is_player = c->IsPlayer();
bool is_car = c->IsCar();
float bullet_born_angle = GlmHelper::CalcAngle(c->GetAttackDir(), GlmHelper::RIGHT);
if (c->GetAttackDir().z > 0.00001f) {
bullet_born_angle = -bullet_born_angle;
}
float old_bullet_born_angle = bullet_born_angle;
GlmHelper::RotateY(bullet_born_offset, bullet_born_angle);
auto transform = glm::rotate(hero_transform,
bullet_born_angle * A8_PI,
glm::vec3(0.0, 1.0, 0.0));
glm::vec4 gun_muzzle_position(0.0, 0.0, 0.0, 0.0);
CalcGunMuzzlePosition(c,
bullet_info.weapon_lv,
bullet_info.weapon_meta,
bullet_info.shot_animi,
gun_muzzle_position,
bullet_info.bullet_idx,
bullet_info.bullet_num);
glm::vec4 v = transform * gun_muzzle_position;
bullet_born_offset = glm::vec3(v.z *10*1, v.y, v.x*10*-1);
{
Buff* buff = c->GetBuffByEffectId(kBET_Scale);
if (buff) {
float param1 = buff->meta->GetBuffParam1(buff);
bullet_born_offset *= param1;
}
}
bullet_info.bullet_born_pos.FromGlmVec3(c->GetPos().ToGlmVec3() + bullet_born_offset);
bullet_info.bullet_dir = c->GetShotDir();
}
int bullet_uniid = 0;
if (mt::Param::s().prebattle_can_use_skill ||
!(c->HasBuffEffect(kBET_Jump) || c->HasBuffEffect(kBET_Fly))) {
bullet_uniid = c->room->CreateBullet
(c,
c->shot_passenger,
bullet_info.weapon_meta,
bullet_info.bullet_meta,
bullet_info.skill_meta,
bullet_info.bullet_born_pos.ToGlmVec3(),
bullet_info.bullet_dir,
bullet_info.fly_distance,
bullet_info.weapon_uniid,
bullet_info.trace_target_uniid,
bullet_info.hand,
bullet_info.keep_shot_animi_timer_ptr,
bullet_info.shot_animi_time,
bullet_info.weapon_buff_id,
bullet_info.reporter_list,
bullet_info.shot_uniid);
#ifdef MYDEBUG1
if (bullet_info.c.Get()->IsPlayer()) {
bullet_info.c.Get()->SendDebugMsg(a8::Format("CreateBullet id:%d",
{bullet_info.weapon_meta->id()}));
}
#endif
}
bullet_uniid = bullet_uniid ? bullet_uniid : c->room->AllocUniid();
#ifdef MYDEBUG1
a8::XPrintf("CreateBullet uniid:%d frameno:%d\n", {bullet_uniid, c->room->GetFrameNo()});
#endif
#ifdef MYDEBUG1
if (c->IsPlayer()) {
a8::XPrintf("bullet_born_pos:%f,%f,%f bullet_dir:%f,%f,%f pos:%f,%f,%f\n",
{
bullet_info.bullet_born_pos.GetX(),
bullet_info.bullet_born_pos.GetY(),
bullet_info.bullet_born_pos.GetZ(),
bullet_info.bullet_dir.x,
bullet_info.bullet_dir.y,
bullet_info.bullet_dir.z,
c->GetPos().GetX(),
c->GetPos().GetY(),
c->GetPos().GetZ(),
});
}
#endif
c->room->frame_event.AddBullet
(bullet_uniid,
c->GetWeakPtrRef(),
bullet_info.weapon_meta,
bullet_info.weapon_lv,
bullet_info.bullet_born_pos.ToGlmVec3(),
bullet_info.bullet_dir,
bullet_info.fly_distance,
bullet_info.trace_target_uniid,
bullet_info.hand,
bullet_info.reporter_list,
bullet_info.shot_uniid);
if (bullet_uniid && (bullet_info.trace_target_uniid || bullet_info.reporter_list)) {
c->room->AddReportBullet(
bullet_uniid
);
}
} else {
std::shared_ptr<BulletInfo> info_copy = std::make_shared<BulletInfo>();
*info_copy = bullet_info;
auto timer = bullet_info.c.Get()->room->xtimer.SetTimeoutWpEx
(
bullet_info.delay_time / FRAME_RATE_MS,
[info_copy] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
info_copy->delay_time = 0;
InternalCreateBullet(*info_copy);
}
},
&bullet_info.c.Get()->xtimer_attacher);
if (!c->room->BattleStarted()) {
c->room->AddToPostBattleAutoFreeList(timer);
}
}
}
void InternalShot(Creature* c,
const mt::Equip* weapon_meta,
const mt::Equip* bullet_meta,
const mt::Skill* skill_meta,
float fly_distance,
long long weapon_uniid,
int trace_target_uniid,
std::function<void(Bullet*)> on_bullet_exit)
{
bool is_player = c->IsPlayer();
bool is_car = c->IsCar();
int weapon_lv = 1;
if (weapon_uniid) {
int p_weapon_lv = 1;
int p_quality = 1;
c->GetNetData()->GetWeaponLvQuality(weapon_uniid, p_weapon_lv, p_quality);
weapon_lv = weapon_lv;
}
int weapon_buff_id = 0;
#if 1
if (c->GetAbility()->HasAttr(kHVAT_ShotRange)) {
if (fly_distance > 0.00001f) {
} else {
fly_distance = weapon_meta->range() * (1 + c->GetAbility()->GetAttr(kHVAT_ShotRange));
}
}
#endif
auto bullet_born_offset_ptr = &weapon_meta->_bullet_born_offset;
if (c->GetCurrWeapon()->meta == weapon_meta) {
if (c->GetCurrWeapon()->bullet_born_offset_ptr) {
bullet_born_offset_ptr = c->GetCurrWeapon()->bullet_born_offset_ptr;
}
weapon_buff_id = c->GetCurrWeapon()->buff_id;
}
for (auto& tuple : *bullet_born_offset_ptr) {
glm::vec3 bullet_born_offset = glm::vec3(std::get<0>(tuple), 0.0f, std::get<1>(tuple));
float bullet_born_angle = GlmHelper::CalcAngle(c->GetAttackDir(), GlmHelper::UP);
if (c->GetAttackDir().x > 0.00001f) {
bullet_born_angle = -bullet_born_angle;
}
GlmHelper::RotateY(bullet_born_offset, bullet_born_angle);
Position bullet_born_pos;
bullet_born_pos.FromGlmVec3(c->GetPos().ToGlmVec3() + bullet_born_offset);
if (c->room->OverBorder(bullet_born_pos.ToGlmVec3(), 0.0f)) {
return;
}
}
int shot_uniid = c->room->GenShotUniid();
c->room->frame_event.AddShot(c->GetWeakPtrRef(), shot_uniid);
int invincible_buff_uniid = 0;
if (weapon_meta->lock_time > 0) {
int buff_uniid = c->TryAddBuff(c, kVertigoBuffId);
Buff* buff = c->GetBuffByUniId(buff_uniid);
if (buff && !buff->remover_timer.expired()) {
c->room->xtimer.ModifyTime(buff->remover_timer, weapon_meta->lock_time / FRAME_RATE_MS);
}
}
if (c->aiming) {
if (weapon_meta->aiming_cast_time() > 0) {
int buff_uniid = c->TryAddBuff(c, kVertigoBuffId);
Buff* buff = c->GetBuffByUniId(buff_uniid);
if (buff && !buff->remover_timer.expired()) {
c->room->xtimer.ModifyTime(buff->remover_timer, weapon_meta->aiming_cast_time() / FRAME_RATE_MS);
}
}
} else {
if (weapon_meta->cast_time() > 0) {
int buff_uniid = c->TryAddBuff(c, kVertigoBuffId);
Buff* buff = c->GetBuffByUniId(buff_uniid);
if (buff && !buff->remover_timer.expired()) {
c->room->xtimer.ModifyTime(buff->remover_timer, weapon_meta->cast_time() / FRAME_RATE_MS);
}
}
}
const mt::HeroShotAnimation* shot_animi = c->GetHeroMeta() ?
c->GetHeroMeta()->GetShotAnimi(weapon_meta->shootfire()) : nullptr;
a8::XTimerWp keep_shot_animi_timer_ptr;
{
int shot_animi_time = (shot_animi ? shot_animi->t : 0);
if (weapon_meta && weapon_meta->equip_subtype() == GUN_SUB_EQUIP_TYPE_FLY_HOOk) {
keep_shot_animi_timer_ptr = c->TryDelayAddBuff(c, kKeepShotAnimiBuffId, shot_animi_time);
}
}
int bulletIdx = 0;
int bulletNum = bullet_born_offset_ptr->size();
for (auto& tuple : *bullet_born_offset_ptr) {
++bulletIdx;
glm::vec3 bullet_born_offset = glm::vec3(std::get<0>(tuple), 0.0f, std::get<1>(tuple));
glm::vec3 bullet_born_pos = c->GetPos().ToGlmVec3() + c->shoot_offset + bullet_born_offset;
glm::vec3 bullet_dir = c->GetShotDir();
float bullet_angle = std::get<2>(tuple);
if (weapon_meta->bullet_angle() >= 0.10f) {
int angle = (int)weapon_meta->bullet_angle() * 1000;
if (angle > 0) {
bullet_angle += (rand() % angle) / 1000.0f * (rand() % 2 == 0 ? 1 : -1);
}
}
if (c->GetAbility()->HasAttr(kHVAT_BulletAngle)&&
c->GetCurrWeapon()->meta == weapon_meta) {
bullet_angle *= 1.0f + c->GetAbility()->GetAttr(kHVAT_BulletAngle);
}
GlmHelper::RotateY(bullet_dir, glm::radians(bullet_angle));
int shot_animi_time = (shot_animi ? shot_animi->t : 0);
if (shot_animi_time > 0) {
shot_animi_time = std::max(100, shot_animi_time);
}
{
float bullet_born_angle = GlmHelper::CalcAngle(c->GetAttackDir(), GlmHelper::UP);
if (c->GetAttackDir().x < 0.00001f) {
bullet_born_angle = -bullet_born_angle;
}
float old_bullet_born_angle = bullet_born_angle;
//GlmHelper::RotateY(bullet_born_offset, bullet_born_angle);
auto transform = glm::rotate(hero_transform,
glm::radians(bullet_born_angle * 180.0f),
glm::vec3(0.0, 1.0, 0.0));
glm::vec4 gun_muzzle_position(0.0, 0.0, 0.0, 0.0);
CalcGunMuzzlePosition(c, weapon_lv, weapon_meta, shot_animi, gun_muzzle_position, bulletIdx, bulletNum);
#ifdef MYDEBUG
gun_muzzle_position +=
glm::vec4(
bullet_born_offset.x / 10.0f,
0,
bullet_born_offset.z / 10.0f,
0
);
#endif
glm::vec4 v = transform * gun_muzzle_position;
bullet_born_offset = glm::vec3(v.x *10*1, v.y, v.z*10*1);
bullet_born_pos = c->GetPos().ToGlmVec3() + bullet_born_offset;
if (c->HasHeightOffset()) {
bullet_born_pos.y += c->GetHeightOffset();
}
if (c->IsPlayer() || c->IsCar()) {
#ifdef MYDEBUG
a8::XPrintf("idx:%d offset:%f,%f,%f angle:%f old_angle:%f angle_xyz:%f,%f,%f %f %f gun_muzzle_position:%f,%f,%f pos:%f,%f,%f gun_id:%d t:%d\n",
{
bulletIdx,
bullet_born_offset.x,
bullet_born_offset.y,
bullet_born_offset.z,
bullet_born_angle,
old_bullet_born_angle,
c->GetAttackDir().x,
c->GetAttackDir().y,
c->GetAttackDir().z,
(bullet_born_angle * 180),
(bullet_born_angle - glm::radians(90.0f) / A8_PI) * 180,
gun_muzzle_position.x,
gun_muzzle_position.y,
gun_muzzle_position.z,
bullet_born_pos.x,
bullet_born_pos.y,
bullet_born_pos.z,
weapon_meta->id(),
shot_animi_time
});
#endif
}
}
{
BulletInfo bullet_info;
bullet_info.c = c->GetWeakPtrRef();
bullet_info.weapon_uniid = weapon_uniid;
bullet_info.weapon_meta = weapon_meta;
bullet_info.skill_meta = skill_meta;
bullet_info.bullet_meta = bullet_meta;
bullet_info.bullet_born_pos.FromGlmVec3(bullet_born_pos);
bullet_info.bullet_dir = bullet_dir;
bullet_info.fly_distance = fly_distance;
bullet_info.delay_time = std::get<3>(tuple);
bullet_info.recoil_force = std::get<4>(tuple);
bullet_info.invincible_buff_uniid = invincible_buff_uniid;
bullet_info.trace_target_uniid = trace_target_uniid;
bullet_info.keep_shot_animi_timer_ptr = keep_shot_animi_timer_ptr;
bullet_info.shot_animi_time = shot_animi_time;
bullet_info.shot_animi = shot_animi;
bullet_info.bullet_idx = bulletIdx;
bullet_info.bullet_num = bulletNum;
bullet_info.weapon_lv = weapon_lv;
bullet_info.weapon_buff_id = weapon_buff_id;
bullet_info.reporter_list = c->CalcReporterList(trace_target_uniid, weapon_meta, bullet_meta);
if (weapon_meta->double_gun() &&
bulletIdx > (int)(bulletNum / 2)) {
bullet_info.hand = 1;
}
#ifdef MYDEBUG1
if (bullet_info.trace_target_uniid) {
a8::XPrintf("bullet trace_target_uniid:%d\n", {bullet_info.trace_target_uniid});
}
#endif
if (bullet_info.skill_meta && bullet_info.skill_meta->_number_meta) {
c->GetTrigger()->SkillBulletPreCreate(bullet_info.delay_time, bullet_info.skill_meta);
}
bullet_info.shot_uniid = shot_uniid;
InternalCreateBullet(bullet_info);
}
}
c->GetTrigger()->Shot(weapon_meta);
if (weapon_meta->recoil_force() > 0.000001) {
c->DoRecoilForce(weapon_meta->recoil_force());
}
if (c->HasBuffEffect(kBET_Hide)) {
c->RemoveHideEffect(kShotReason);
}
if (trace_target_uniid) {
c->LockAttackDir(1000);
}
if (!c->nature_recover_hp_idle_timer.expired()) {
c->room->xtimer.FireEvent
(
c->nature_recover_hp_idle_timer,
kRemoveNatureRecoverTimerEvent,
nullptr);
}
if (c->aiming) {
c->aiming = false;
c->aiming_frameno = 0;
if (!c->GetCurrWeapon()->meta->IsMultistageGun()) {
c->power_idx = -1;
}
c->ClearAimingBuffs();
}
if (c->skill_hold_skill_id != 0) {
c->ClearSkillHoldState();
}
if (weapon_meta->id() == 20611) {
float angle = GlmHelper::CalcAngle(c->GetAttackDir(), GlmHelper::UP);
std::shared_ptr<std::vector<float>> buff_vars = std::make_shared<std::vector<float>>
(
);
if (c->GetAttackDir().x < 0.00001f) {
angle = -angle;
}
buff_vars->push_back(c->GetPos().ToGlmVec3().x);
buff_vars->push_back(c->GetPos().ToGlmVec3().y);
buff_vars->push_back(c->GetPos().ToGlmVec3().z);
buff_vars->push_back(angle);
c->TryAddBuff(c,
8060,
nullptr,
nullptr,
buff_vars
);
}
}