#include "precompile.h" #include #include #include #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> 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 info_copy = std::make_shared(); *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) { 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()->GetAttrAddition(kHVAT_ShotRange) > 0.00001f) { if (fly_distance > 0.00001f) { } else { fly_distance = weapon_meta->range() * (1 + c->GetAbility()->GetAttrAddition(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()->GetAttrRuduce(kHVAT_BulletAngle) > 0.0f && c->GetCurrWeapon()->meta == weapon_meta) { bullet_angle *= 1.0f - c->GetAbility()->GetAttrRuduce(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; #if 0 if (skill_meta && (skill_meta->GetMagicId() == MAGIC_20101_HL || skill_meta->GetMagicId() == MAGIC_20201_HX) ) { bullet_info.trace_target_uniid = c->GetSkillTargetId(); } #endif 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> buff_vars = std::make_shared> ( ); 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 ); } }