aozhiwei 69a000d24f 1
2023-04-10 18:33:32 +08:00

1043 lines
32 KiB
C++

#include "precompile.h"
#include <math.h>
#include "netdata.h"
#include "human.h"
#include "creature.h"
#include "types.h"
#include "bullet.h"
#include "app.h"
#include "room.h"
#include "explosion.h"
#include "roommgr.h"
#include "ability.h"
#include "stats.h"
#include "android.h"
#include "buff/distance_dmg_addition.h"
#include "mt/Param.h"
#include "mt/Item.h"
#include "mt/Hero.h"
#include "mt/HeroQuality.h"
#include "mt/GunQuality.h"
#include "mt/NpcStandard.h"
#include "mt/PveGemini.h"
#include "mt/PveGeminiContent.h"
#include "mt/Equip.h"
#include "mt/Skill.h"
#include "mt/SkillNumber.h"
#include "mt/FormulaPvp.h"
#include "mt/Robot.h"
#include "attrhelper.h"
struct CalcDmgContext
{
int is_crit = 0;
float crit_dmg = 0.0f;
};
static CalcDmgContext g_calc_dmg_context = {0};
class HeroAbility
{
public:
long long hero_uniid_ = 0;
const mt::Hero* hero_meta = nullptr;
std::shared_ptr<a8::XObject> hero_dto;
int spec_skill_id = 0;
float GetHP()
{
return hp_;
}
float GetAtk()
{
return atk_;
}
float GetDef()
{
return def_;
}
float GetCritAtk()
{
return crit_atk_;
}
float GetCritAtkRatio()
{
return crit_atk_ratio_;
}
float GetDodge()
{
return dodge_;
}
float GetDodgeDamageRuduce()
{
return dodge_damage_ruduce_;
}
float GetBrainLifePct()
{
return brain_life_pct_;
}
float GetSkillCdPct()
{
return skill_cd_pct_;
}
float GetRescueTimePct()
{
return rescue_time_pct_;
}
float GetDrugTimePct()
{
return durg_time_pct_;
}
float GetDrugEfficacyPct()
{
return durg_eff_pct_;
}
float GetTenacityPct()
{
return tenacity_pct_;
}
float GetRecoverHpAdd()
{
return recover_hp_add_pct_;
}
void Init(Creature* c)
{
if (hero_dto) {
DtoInit(c);
} else {
DefaultInit(c);
}
}
private:
void DefaultInit(Creature* c)
{
hp_ = hero_meta->hp();
atk_ = hero_meta->damage();
def_ = hero_meta->defence();
crit_atk_ = hero_meta->crit_atk();
crit_atk_ratio_ = hero_meta->crit_atk_ratio();
dodge_ = hero_meta->miss();
dodge_damage_ruduce_ = hero_meta->miss_damage_ruduce();
if (c->room->pve_instance) {
const mt::NpcStandard* standard_meta = mt::NpcStandard::GetById
(c->room->pve_instance->gemini_lv());
if (standard_meta) {
hp_ = standard_meta->hp() * hero_meta->hp_ratio() *
c->room->pve_instance->GetHpMul(c->room->GetHumanNum());
atk_ = standard_meta->damage() * hero_meta->damage_ratio();
def_ = standard_meta->defence() * hero_meta->defence_ratio();
} else {
#ifdef DEBUG
abort();
#endif
}
}
}
void DtoInit(Creature* c)
{
std::array<float, kHAT_End> base_attr_abs = {0};
std::array<float, kHAT_End> base_attr_rate = {0};
std::array<float, kHAT_End> pro_attr_abs = {0};
std::array<float, kHAT_End> pro_attr_rate = {0};
std::array<float, kHAT_End> skill_attr_abs = {0};
std::array<float, kHAT_End> skill_attr_rate = {0};
std::array<float, kHAT_End> chip_attr_abs = {0};
std::array<float, kHAT_End> chip_attr_rate = {0};
std::array<float, kHAT_End> core_attr_abs = {0};
std::array<float, kHAT_End> core_attr_rate = {0};
{
std::shared_ptr<a8::XObject> attr_base_xobj = hero_dto->At("attr_base");
if (attr_base_xobj && attr_base_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_base_xobj, base_attr_abs, base_attr_rate);
}
}
{
std::shared_ptr<a8::XObject> attr_base_xobj = hero_dto->At("rand_attr");
if (attr_base_xobj && attr_base_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_base_xobj, base_attr_abs, base_attr_rate);
}
}
{
std::shared_ptr<a8::XObject> attr_pro_xobj = hero_dto->At("attr_pro");
if (attr_pro_xobj && attr_pro_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_pro_xobj, pro_attr_abs, pro_attr_rate);
}
}
{
std::shared_ptr<a8::XObject> attr_skill_xobj = hero_dto->At("attr_skill");
if (attr_skill_xobj && attr_skill_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_skill_xobj, skill_attr_abs, skill_attr_rate);
}
}
{
std::shared_ptr<a8::XObject> attr_chip_xobj = hero_dto->At("attr_chip");
if (attr_chip_xobj && attr_chip_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_chip_xobj, chip_attr_abs, chip_attr_rate);
}
}
{
std::shared_ptr<a8::XObject> attr_core_xobj = hero_dto->At("attr_core");
if (attr_core_xobj && attr_core_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_core_xobj, core_attr_abs, core_attr_rate);
}
}
std::array<float, kHAT_End> finaly_attr_abs = base_attr_abs;
std::array<float, kHAT_End> finaly_attr_rate = base_attr_rate;
for (int i = 0; i < kHAT_End; ++i) {
if (pro_attr_abs[i] > 0.000f) {
finaly_attr_abs[i] = pro_attr_abs[i];
}
if (pro_attr_rate[i] > 0.000f) {
finaly_attr_rate[i] = pro_attr_rate[i];
}
finaly_attr_abs[i] += skill_attr_abs[i];
finaly_attr_rate[i] += skill_attr_rate[i];
finaly_attr_abs[i] += chip_attr_abs[i];
finaly_attr_rate[i] += chip_attr_rate[i];
finaly_attr_abs[i] += core_attr_abs[i];
finaly_attr_rate[i] += core_attr_rate[i];
}
{
hp_ = finaly_attr_abs[kHAT_Hp] + base_attr_abs[kHAT_Hp] * finaly_attr_rate[kHAT_HP_RATE];
atk_ = finaly_attr_abs[kHAT_Atk] + base_attr_abs[kHAT_Atk] * finaly_attr_rate[kHAT_ATK_RATE];
def_ = finaly_attr_abs[kHAT_Def] + base_attr_abs[kHAT_Def] * finaly_attr_rate[kHAT_DEF_RATE];
crit_atk_ = finaly_attr_rate[kHAT_CRIT] * 1000;
crit_atk_ratio_ = finaly_attr_rate[kHAT_CRIT_DAMAGE_RATE];
dodge_ = finaly_attr_rate[kHAT_DODGE];
dodge_damage_ruduce_ = finaly_attr_rate[kHAT_DODGE_DAMAGE_RATE];
brain_life_pct_ = finaly_attr_rate[kHAT_BrainLifePct];
skill_cd_pct_ = finaly_attr_rate[kHAT_SkillTime];
rescue_time_pct_ = finaly_attr_rate[kHAT_RescueTime];
durg_time_pct_ = finaly_attr_rate[kHAT_DrugTime];
durg_eff_pct_ = finaly_attr_rate[kHAT_DrugEfficacy];
tenacity_pct_ = finaly_attr_rate[kHAT_Tenacity];
recover_hp_add_pct_ = finaly_attr_rate[kHAT_RecoverHpAdd];
}
}
private:
float hp_ = 0.0f;
float atk_ = 0.0f;
float def_ = 0.0f;
float crit_atk_ = 0.0f;
float crit_atk_ratio_ = 0.0f;
float dodge_ = 0.0f;
float dodge_damage_ruduce_ = 0.0f;
float brain_life_pct_ = 0.0f;
float skill_cd_pct_ = 0.0f;
float rescue_time_pct_ = 0.0f;
float durg_time_pct_ = 0.0f;
float durg_eff_pct_ = 0.0f;
float tenacity_pct_ = 0.0f;
float recover_hp_add_pct_ = 0.0f;
};
class WeaponAbility
{
public:
long long weapon_uniid = 0;
int weapon_lv = 1;
int quality = 1;
const mt::Equip* weapon_meta = nullptr;
std::shared_ptr<a8::XObject> weapon_dto;
float GetAtk()
{
return atk_;
}
float GetCritAtk()
{
return crit_atk_;
}
float GetCritAtkRatio()
{
return crit_atk_ratio_;
}
int GetClipVolume()
{
return clip_volume_;
}
int GetFireRate()
{
return fire_rate_;
}
int GetReloadTime()
{
return reload_time_;
}
void Init(Creature* c)
{
if (weapon_dto) {
DtoInit(c);
} else {
DefaultInit(c);
}
}
private:
void DefaultInit(Creature* c)
{
atk_ = weapon_meta->_atk;
crit_atk_ = weapon_meta->critical();
crit_atk_ratio_ = weapon_meta->cri_damage();
clip_volume_ = weapon_meta->clip_volume();
fire_rate_ = weapon_meta->fire_rate();
reload_time_ = weapon_meta->reload_time();
}
void DtoInit(Creature* c)
{
std::array<float, kHAT_End> base_attr_abs = {0};
std::array<float, kHAT_End> base_attr_rate = {0};
std::array<float, kHAT_End> pro_attr_abs = {0};
std::array<float, kHAT_End> pro_attr_rate = {0};
std::array<float, kHAT_End> chip_attr_abs = {0};
std::array<float, kHAT_End> chip_attr_rate = {0};
std::array<float, kHAT_End> core_attr_abs = {0};
std::array<float, kHAT_End> core_attr_rate = {0};
{
std::shared_ptr<a8::XObject> attr_base_xobj = weapon_dto->At("attr_base");
if (attr_base_xobj && attr_base_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_base_xobj, base_attr_abs, base_attr_rate);
}
}
{
std::shared_ptr<a8::XObject> attr_base_xobj = weapon_dto->At("rand_attr");
if (attr_base_xobj && attr_base_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_base_xobj, base_attr_abs, base_attr_rate);
}
}
{
std::shared_ptr<a8::XObject> attr_pro_xobj = weapon_dto->At("attr_pro");
if (attr_pro_xobj && attr_pro_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_pro_xobj, pro_attr_abs, pro_attr_rate);
}
}
{
std::shared_ptr<a8::XObject> attr_chip_xobj = weapon_dto->At("attr_chip");
if (attr_chip_xobj && attr_chip_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_chip_xobj, chip_attr_abs, chip_attr_rate);
}
}
{
std::shared_ptr<a8::XObject> attr_core_xobj = weapon_dto->At("attr_core");
if (attr_core_xobj && attr_core_xobj->IsArray()) {
AttrHelper::ParseAttr(attr_core_xobj, core_attr_abs, core_attr_rate);
}
}
std::array<float, kHAT_End> finaly_attr_abs = base_attr_abs;
std::array<float, kHAT_End> finaly_attr_rate = base_attr_rate;
for (int i = 0; i < kHAT_End; ++i) {
if (pro_attr_abs[i] > 0.000f) {
finaly_attr_abs[i] = pro_attr_abs[i];
}
if (pro_attr_rate[i] > 0.000f) {
finaly_attr_rate[i] = pro_attr_rate[i];
}
finaly_attr_abs[i] += chip_attr_abs[i];
finaly_attr_rate[i] += chip_attr_rate[i];
finaly_attr_abs[i] += core_attr_abs[i];
finaly_attr_rate[i] += core_attr_rate[i];
}
atk_ = finaly_attr_abs[kHAT_Atk] + base_attr_abs[kHAT_Atk] * finaly_attr_rate[kHAT_ATK_RATE];
crit_atk_ = finaly_attr_rate[kHAT_CRIT] * 1000;
crit_atk_ratio_ = finaly_attr_rate[kHAT_CRIT_DAMAGE_RATE];
clip_volume_ = finaly_attr_abs[kHAT_Volume];
fire_rate_ = finaly_attr_abs[kHAT_FireRate];
reload_time_ = finaly_attr_abs[kHAT_ReloadTime];
}
private:
float atk_ = 0.0f;
float crit_atk_ = 0.0f;
float crit_atk_ratio_ = 0.0f;
int clip_volume_ = 0;
int fire_rate_ = 0;
int reload_time_ = 0;
};
BattleDataContext::BattleDataContext()
{
hero_ability_ = std::make_shared<HeroAbility>();
hero_ability_->hero_meta = mt::Param::s().human_meta;
}
void BattleDataContext::Clear()
{
}
void BattleDataContext::ParseResult(a8::XObject& obj)
{
is_valid_battle = obj.Get("is_valid_battle");
payload = obj.Get("payload").GetString();
errcode = obj.Get("errcode");
errmsg = obj.Get("errmsg").GetString();
if (errcode == 0) {
revive_coin_ = obj.Get("revive_coin");
match_mode_ = obj.Get("match_mode");
}
level_ = obj.HasKey("level") ? obj.Get("level").GetInt() : 1;
skin_id_ = obj.HasKey("hero_skin") ? obj.Get("hero_skin").GetInt() : 0;
if (obj.HasKey("hero_dto") && obj.At("hero_dto")->IsObject()) {
hero_dto = obj.At("hero_dto");
hero_ability_->hero_uniid_ = hero_dto->Get("hero_uniid", "");
hero_ability_->spec_skill_id = obj.Get("skill_id", "");
hero_ability_->hero_dto = hero_dto;
hero_lv_ = hero_dto->HasKey("hero_lv") ? hero_dto->Get("hero_lv").GetInt() : 1;
const mt::Hero* meta = mt::Hero::GetById(hero_dto->Get("hero_id", ""));
if (meta) {
hero_ability_->hero_meta = meta;
}
}
if (obj.HasKey("weapon_dto1") && obj.At("weapon_dto1")->IsObject()) {
weapon_dto1 = obj.At("weapon_dto1");
const mt::Item* item_meta = mt::Item::GetById(weapon_dto1->Get("gun_id", 0));
if (item_meta) {
const mt::Equip* meta = mt::Equip::GetById(item_meta->relationship());
if (meta) {
weapon1_ability_ = std::make_shared<WeaponAbility>();
weapon1_ability_->weapon_uniid = weapon_dto1->Get("gun_uniid", 0);
weapon1_ability_->weapon_lv = weapon_dto1->Get("gun_lv", 1);
weapon1_ability_->quality = weapon_dto1->Get("quality", 1);
weapon1_ability_->weapon_meta = meta;
weapon1_ability_->weapon_dto = weapon_dto1;
}
}
}
if (obj.HasKey("weapon_dto2") && obj.At("weapon_dto2")->IsObject()) {
weapon_dto2 = obj.At("weapon_dto2");
const mt::Item* item_meta = mt::Item::GetById(weapon_dto2->Get("gun_id", 0));
if (item_meta) {
const mt::Equip* meta = mt::Equip::GetById(item_meta->relationship());
if (meta) {
weapon2_ability_ = std::make_shared<WeaponAbility>();
weapon2_ability_->weapon_uniid = weapon_dto2->Get("gun_uniid", 0);
weapon2_ability_->weapon_lv = weapon_dto2->Get("gun_lv", 1);
weapon2_ability_->quality = weapon_dto2->Get("quality", 1);
weapon2_ability_->weapon_meta = meta;
weapon2_ability_->weapon_dto = weapon_dto2;
}
}
}
parse_ok = hero_ability_->hero_meta != nullptr;
}
void BattleDataContext::GetHeroLvQuality(long long& hero_uniid, int& hero_lv, int& quality)
{
hero_uniid = 0;
hero_lv = 1;
quality = 1;
if (owner_.Get()->IsPlayer()) {
if (hero_ability_ && hero_dto && hero_dto->IsObject()) {
hero_uniid = hero_dto->Get("hero_uniid", 0).GetInt64();
hero_lv = hero_dto->Get("hero_lv", 0).GetInt();
quality = hero_dto->Get("quality", 0).GetInt();
}
}
}
void BattleDataContext::GetWeaponLvQuality(long long weapon_uniid, int& weapon_lv, int& quality)
{
weapon_lv = 1;
quality = 1;
if (owner_.Get()->IsPlayer() && weapon_uniid) {
if (weapon1_ability_ && weapon_uniid == weapon1_ability_->weapon_uniid) {
weapon_lv = weapon1_ability_->weapon_lv;
quality = weapon1_ability_->quality;
}
if (weapon2_ability_ && weapon_uniid == weapon2_ability_->weapon_uniid) {
weapon_lv = weapon2_ability_->weapon_lv;
quality = weapon2_ability_->quality;
}
}
}
int BattleDataContext::GetWeaponMaxLv()
{
int max_weapon_lv = 1;
if (weapon1_ability_) {
max_weapon_lv = std::max(max_weapon_lv, weapon_dto1->Get("gun_lv", 0).GetInt());
}
if (weapon2_ability_) {
max_weapon_lv = std::max(max_weapon_lv, weapon_dto2->Get("gun_lv", 0).GetInt());
}
return std::max(1, max_weapon_lv);
}
void BattleDataContext::CalcBattleStat(struct PlayerStats* stats)
{
if (!owner_.Get()->IsPlayer()) {
return;
}
auto CalcHeroPvpCeg =
[] (long long ceg_uplimit, struct PlayerStats* stats) -> long long
{
const mt::FormulaPvp* meta = mt::FormulaPvp::GetByTopx(stats->ranked_topx);
if (!meta) {
return 0;
}
long long ceg = round
(
ceg_uplimit *
(
(0.5 * stats->ranked_topx * meta->ranked_topx()) +
(0.25 * stats->kills_topx * meta->kills_topx()) +
(0.15 * stats->hero_topx * meta->hero_topx()) +
(0.5 * stats->weapon_topx * meta->weapon_topx()) +
(0.5 * stats->survival_topx * meta->survival_topx())
)
);
return ceg;
};
auto CalcWeaponPvpCeg =
[] (long long ceg_uplimit, struct PlayerStats* stats) -> long long
{
const mt::FormulaPvp* meta = mt::FormulaPvp::GetByTopx(stats->ranked_topx);
if (!meta) {
return 0;
}
long long ceg = round
(
ceg_uplimit *
(
(0.5 * stats->ranked_topx * meta->ranked_topx()) +
(0.25 * stats->kills_topx * meta->kills_topx()) +
(0.15 * stats->hero_topx * meta->hero_topx()) +
(0.5 * stats->weapon_topx * meta->weapon_topx()) +
(0.5 * stats->survival_topx * meta->survival_topx())
)
);
return ceg;
};
if (hero_ability_ && hero_dto && hero_dto->IsObject()) {
int hero_id = hero_dto->Get("hero_id", 0).GetInt();
int quality = hero_dto->Get("quality", 0).GetInt();
int today_get_gold = hero_dto->Get("today_get_gold", 0).GetInt();
const mt::Hero* hero_meta = mt::Hero::GetById(hero_id);
const mt::HeroQuality* quality_meta = mt::HeroQuality::GetById(quality);
stats->pb_hero_stats.hero_uniid = a8::XValue(hero_ability_->hero_uniid_).GetString();
stats->pb_hero_stats.hero_id = hero_id;
stats->pb_hero_stats.hero_name = hero_meta ? hero_meta->name() : "";
if (quality_meta) {
int up_limit = quality_meta->GetPvpCegUpLimit();
int ceg = CalcHeroPvpCeg(up_limit, stats);
int new_ceg = std::min(up_limit, today_get_gold + ceg);
int finaly_ceg = std::max(0, new_ceg - today_get_gold);
stats->pb_hero_stats.ceg_uplimit = up_limit;
stats->pb_hero_stats.today_get_ceg =
std::min(up_limit, today_get_gold + finaly_ceg);
stats->pb_hero_stats.reward_ceg = finaly_ceg;
}
}
std::vector<std::shared_ptr<a8::XObject>> weapons;
if (weapon_dto1) {
weapons.push_back(weapon_dto1);
}
if (weapon_dto2) {
weapons.push_back(weapon_dto2);
}
for (auto& weapon_dto : weapons) {
std::string gun_uniid = weapon_dto->Get("gun_uniid", 0).GetString();
int gun_id = weapon_dto->Get("gun_id", 0).GetInt();
int quality = weapon_dto->Get("quality", 0).GetInt();
int today_get_gold = weapon_dto->Get("today_get_gold", 0).GetInt();
const mt::Item* item_meta = mt::Item::GetById(gun_id);
const mt::GunQuality* quality_meta = mt::GunQuality::GetById(quality);
auto& p = a8::FastAppend(stats->pb_weapons_stats);
p.weapon_uniid = gun_uniid;
p.weapon_id = gun_id;
p.weapon_name = item_meta ? item_meta->name() : "";
if (quality_meta) {
int up_limit = quality_meta->GetPvpCegUpLimit();
int ceg = CalcWeaponPvpCeg(up_limit, stats);
int new_ceg = std::min(up_limit, today_get_gold + ceg);
int finaly_ceg = std::max(0, new_ceg - today_get_gold);
p.ceg_uplimit = up_limit;
p.today_get_ceg =
std::min(up_limit, today_get_gold + finaly_ceg);
p.reward_ceg = finaly_ceg;
}
}
}
float BattleDataContext::CalcDmg(Creature* target, IBullet* bullet)
{
g_calc_dmg_context = {0};
g_calc_dmg_context.is_crit = IsCrit(bullet) ? 1 : 0;
if (owner_.Get()->IsEntityType(ET_Hero)) {
int i = 0;
}
float total_atk = GetTotalAtk(bullet);
if (bullet->GetSkillMeta() && bullet->GetSkillMeta()->_number_meta) {
switch (bullet->GetSkillMeta()->GetMagicId()) {
case MAGIC_20201_HX:
{
total_atk = bullet->GetSkillMeta()->_number_meta->damage() +
bullet->GetSkillMeta()->_number_meta->damage_addition() * GetHeroTotalAtk();
}
break;
default:
{
}
break;
}
}
float normal_dmg = total_atk *
(1 - target->GetBattleContext()->GetDef() / (target->GetBattleContext()->GetDef() + 200));
if (g_calc_dmg_context.is_crit) {
normal_dmg *= 1.5;
}
float finaly_dmg = normal_dmg;
float dmg_addition = 0.0f;
Buff* buff = owner_.Get()->GetBuffByEffectId(kBET_DistanceDmgAddition);
if (buff) {
DistanceDmgAdditionBuff* spec_buff = (DistanceDmgAdditionBuff*)buff;
float distance = owner_.Get()->GetPos().Distance2D2(target->GetPos());
if (distance > spec_buff->distance && spec_buff->distance > 0.00001f) {
dmg_addition += std::max(10.0f, (distance / spec_buff->distance) * spec_buff->add);
} else {
dmg_addition += spec_buff->min_add;
}
#ifdef DEBUG
if (owner_.Get() && owner_.Get()->IsPlayer()) {
owner_.Get()->SendDebugMsg(a8::Format("兔子被动 distance:%f dmg_addition:%f",
{
distance,
dmg_addition
}));
}
#endif
}
dmg_addition += owner_.Get()->GetAbility()->GetAttrAddition(kHVAT_Dmg);
finaly_dmg *= (1 + dmg_addition); //连加
finaly_dmg *= (1 - target->GetAbility()->GetAttrRuduce(kHVAT_Dmg)); //(1-减免) 连乘
#if 1
if (owner_.Get()->IsAndroid() && owner_.Get()->AsAndroid()->robot_meta->dmg_ratio() > 0.0001f) {
finaly_dmg *= owner_.Get()->AsAndroid()->robot_meta->dmg_ratio();
}
#endif
finaly_dmg = std::max(1.0f, finaly_dmg);
if (g_calc_dmg_context.is_crit) {
g_calc_dmg_context.crit_dmg = finaly_dmg;
}
return std::round(finaly_dmg);
}
float BattleDataContext::CalcDmg(Obstacle* target, IBullet* bullet)
{
g_calc_dmg_context = {0};
g_calc_dmg_context.is_crit = IsCrit(bullet) ? 1 : 0;
float total_atk = GetTotalAtk(bullet);
float normal_dmg = total_atk * (1 - 0 / 1000);
float crit = g_calc_dmg_context.is_crit ? GetCritRate(bullet) : 0;
float dodge = IsDodge(bullet) ? GetDodgeRuduce(bullet) : 0;
float finaly_dmg = normal_dmg * (1.0f + crit + dodge);
#ifdef DEBUG
if (owner_.Get()->IsPlayer()) {
std::string data = a8::Format
("数值: 子弹攻击物件 total_atk:%f normal_dmg:%f crit:%f dodge:%f finaly_dmg:%f target_def:%f",
{
total_atk,
normal_dmg,
crit,
dodge,
finaly_dmg,
0
});
owner_.Get()->SendDebugMsg(data);
}
#endif
if (g_calc_dmg_context.is_crit) {
g_calc_dmg_context.crit_dmg = finaly_dmg;
}
return finaly_dmg;
}
float BattleDataContext::CalcReceiveDmg(Creature* sender, float normal_dmg)
{
float finaly_dmg = normal_dmg *
(1 - owner_.Get()->GetBattleContext()->GetDef() / (sender->GetBattleContext()->GetDef() + 200));
finaly_dmg *= (1 + sender->GetAbility()->GetAttrAddition(kHVAT_Dmg)); //连加
finaly_dmg *= (1 - owner_.Get()->GetAbility()->GetAttrRuduce(kHVAT_Dmg)); //(1-减免) 连乘
finaly_dmg = std::max(1.0f, finaly_dmg);
return std::round(finaly_dmg);
}
float BattleDataContext::CalcDmg(Explosion* e)
{
g_calc_dmg_context = {0};
float finaly_dmg = e->GetDmg();
#ifdef DEBUG
if (owner_.Get()->IsPlayer()) {
std::string data = a8::Format
("数值: 爆炸伤害 finaly_dmg:%f def:%f",
{
finaly_dmg,
GetDef()
});
owner_.Get()->SendDebugMsg(data);
}
#endif
return finaly_dmg;
}
float BattleDataContext::GetTotalAtk(IBullet* bullet)
{
float total_atk = (GetHeroTotalAtk() / 100) * GetWeaponAtk(bullet);
return total_atk;
}
float BattleDataContext::GetHP()
{
return hero_ability_->GetHP();
}
float BattleDataContext::GetMaxHP()
{
return hero_ability_->GetHP();
}
float BattleDataContext::GetDef()
{
float def = hero_ability_->GetDef();
def += owner_.Get()->GetAbility()->GetAttrAbs(kHAT_Def);
def *= 1.0f + owner_.Get()->GetAbility()->GetAttrRate(kHAT_Def);
def *= 1.0f + owner_.Get()->GetAbility()->GetAttrAddition(kHAT_Def) -
owner_.Get()->GetAbility()->GetAttrRuduce(kHAT_Def);
return def;
}
float BattleDataContext::GetHeroTotalAtk()
{
float atk = hero_ability_->GetAtk();
atk += owner_.Get()->GetAbility()->GetAttrAbs(kHAT_Atk);
atk *= 1.0f + owner_.Get()->GetAbility()->GetAttrRate(kHAT_Atk);
atk *= 1.0f + owner_.Get()->GetAbility()->GetAttrAddition(kHAT_Atk) -
owner_.Get()->GetAbility()->GetAttrRuduce(kHAT_Atk);
return atk;
}
float BattleDataContext::GetWeaponAtk(IBullet* bullet)
{
float atk = 0.0f;
auto weapon = GetWeaponByUniId(bullet->GetWeaponUniId());
if (weapon) {
atk = weapon->GetAtk();
} else {
atk = bullet->GetGunMeta()->_atk;
}
atk *= (1 + owner_.Get()->GetAbility()->GetAttrAddition(kHVAT_WeaponAtk));
return atk;
}
bool BattleDataContext::IsCrit(IBullet* bullet)
{
int rnd = a8::RandEx(0, 1000 - 1);
return GetCrit(bullet) > rnd;;
}
bool BattleDataContext::IsDodge(IBullet* bullet)
{
int rnd = a8::RandEx(0, 1000 - 1);
return GetDodge(bullet) > rnd;;
}
float BattleDataContext::GetCritRate(IBullet* bullet)
{
auto weapon = GetWeaponByUniId(bullet ? bullet->GetWeaponUniId() : 0);
return hero_ability_->GetCritAtkRatio() + (weapon ? weapon->GetCritAtkRatio() : 0);
}
float BattleDataContext::GetDodgeRuduce(IBullet* bullet)
{
return hero_ability_->GetDodgeDamageRuduce();
}
std::shared_ptr<WeaponAbility> BattleDataContext::GetWeaponByUniId(long long weapon_uuid)
{
if (weapon1_ability_ && weapon1_ability_->weapon_uniid == weapon_uuid) {
return weapon1_ability_;
}
if (weapon2_ability_ && weapon2_ability_->weapon_uniid == weapon_uuid) {
return weapon2_ability_;
}
return nullptr;
}
void BattleDataContext::ForceInit(long long hero_uniid,
const mt::Hero* hum_meta,
long long weapon1_uniid,
const mt::Equip* weapon1_meta,
long long weapon2_uniid,
const mt::Equip* weapon2_meta)
{
hero_ability_->hero_uniid_ = hero_uniid;
hero_ability_->hero_meta = hum_meta;
if (weapon1_uniid && weapon1_meta) {
weapon1_ability_ = std::make_shared<WeaponAbility>();
weapon1_ability_->weapon_uniid = weapon1_uniid;
weapon1_ability_->weapon_meta = weapon1_meta;
}
if (weapon2_uniid && weapon2_meta) {
weapon2_ability_ = std::make_shared<WeaponAbility>();
weapon2_ability_->weapon_uniid = weapon2_uniid;
weapon2_ability_->weapon_meta = weapon2_meta;
}
}
void BattleDataContext::Init(Creature* c)
{
owner_ = c->GetWeakPtrRef();
if (!hero_ability_->hero_uniid_) {
hero_ability_->hero_uniid_ = App::Instance()->AllocTempHeroUniId();
}
hero_ability_->Init(c);
if (weapon1_ability_) {
weapon1_ability_->Init(c);
}
if (weapon2_ability_) {
weapon2_ability_->Init(c);
}
if (skin_id_ && c->IsHuman()) {
const mt::Item* item_meta = mt::Item::GetById(skin_id_);
if (item_meta) {
Skin* skin = c->AsHuman()->GetSkinByIdx(0);
skin->skin_id = item_meta->skinid();
}
}
if (c->IsPlayer()) {
std::array<std::shared_ptr<WeaponAbility>, 2> weapons = {weapon1_ability_, weapon2_ability_};
for (auto weapon : weapons) {
if (weapon) {
Weapon& spec_weapon = a8::FastAppend(c->AsHuman()->spec_weapons);
spec_weapon.weapon_uniid = a8::XValue(weapon->weapon_uniid);
spec_weapon.weapon_id = weapon->weapon_meta->id();
spec_weapon.meta = weapon->weapon_meta;
spec_weapon.Recalc();
spec_weapon.ammo = spec_weapon.GetClipVolume(c);
}
}
}
c->NetInitOk();
}
void BattleDataContext::GetSkillList(std::vector<int>& skill_list)
{
const mt::Skill* spec_skill = mt::Skill::GetById(hero_ability_->spec_skill_id);
const mt::Skill* skill1 = mt::Skill::GetById(hero_ability_->hero_meta->skill1list());
const mt::Skill* skill2 = mt::Skill::GetById(hero_ability_->hero_meta->skill2list());
const mt::Skill* skill3 = mt::Skill::GetById(hero_ability_->hero_meta->skill3list());
if (skill1 && skill2 && skill3 && skill1_lv > 0 && skill2_lv > 0 && skill3_lv > 0) {
if (mt::Skill::GetById(skill1->skill_id() + skill1_lv - 1)) {
skill_list.push_back(skill1->skill_id() + skill1_lv - 1);
} else {
skill_list.push_back(skill1->skill_id());
}
//替换翻滚
if (spec_skill) {
skill_list.push_back(spec_skill->skill_id());
} else {
if (mt::Skill::GetById(skill2->skill_id() + skill2_lv - 2)) {
skill_list.push_back(skill2->skill_id() + skill2_lv - 2);
} else {
skill_list.push_back(skill2->skill_id());
}
}
if (mt::Skill::GetById(skill3->skill_id() + skill3_lv - 3)) {
skill_list.push_back(skill3->skill_id() + skill3_lv - 3);
} else {
skill_list.push_back(skill3->skill_id());
}
}
}
float BattleDataContext::GetCrit(IBullet* bullet)
{
auto weapon = GetWeaponByUniId(bullet ? bullet->GetWeaponUniId() : 0);
return hero_ability_->GetCritAtk() + (weapon ? weapon->GetCritAtk() : 0);
}
float BattleDataContext::GetDodge(IBullet* bullet)
{
return hero_ability_->GetDodge();
}
int BattleDataContext::GetClipVolume(Creature* c, Weapon* weapon)
{
if (!weapon->meta) {
return 0;
}
auto p = GetWeaponByUniId(weapon->weapon_uniid);
return p ? p->GetClipVolume() : weapon->meta->clip_volume();
}
int BattleDataContext::GetFireRate(Creature* c, Weapon* weapon)
{
if (!weapon->meta) {
return 0;
}
auto p = GetWeaponByUniId(weapon->weapon_uniid);
return p ? p->GetFireRate() : weapon->meta->fire_rate();
}
int BattleDataContext::GetReloadTime(Creature* c, Weapon* weapon)
{
if (!weapon->meta) {
return 0;
}
auto p = GetWeaponByUniId(weapon->weapon_uniid);
return p ? p->GetReloadTime() : weapon->meta->reload_time();
}
float BattleDataContext::GetExtRecoverHp()
{
return 0;
}
void BattleDataContext::SetReviveCoin(int num)
{
revive_coin_ = num;
}
int BattleDataContext::GetReviveCoin()
{
return revive_coin_;
}
void BattleDataContext::SetMatchMode(int match_mode)
{
match_mode_ = match_mode;
}
int BattleDataContext::GetMatchMode()
{
return match_mode_;
}
bool BattleDataContext::IsCrit()
{
return g_calc_dmg_context.is_crit ? 1 : 0;
}
float BattleDataContext::GetCritDmg()
{
return g_calc_dmg_context.crit_dmg;
}
int BattleDataContext::GetSkinId()
{
return skin_id_;
}
int BattleDataContext::GetLevel()
{
return std::max(level_, 1);
}
float BattleDataContext::GetBrainLifePct()
{
return hero_ability_->GetBrainLifePct();
}
float BattleDataContext::GetSkillCdPct()
{
return hero_ability_->GetSkillCdPct() + owner_.Get()->GetAbility()->GetAttrAddition(kHAT_SkillTime);
}
float BattleDataContext::GetRescueTimePct()
{
return hero_ability_->GetRescueTimePct();
}
float BattleDataContext::GetDrugTimePct()
{
return hero_ability_->GetDrugTimePct();
}
float BattleDataContext::GetDrugEfficacyPct()
{
return hero_ability_->GetDrugEfficacyPct();
}
float BattleDataContext::GetTenacityPct()
{
return hero_ability_->GetTenacityPct();
}
float BattleDataContext::GetRecoverHpAdd()
{
return hero_ability_->GetRecoverHpAdd();
}
int BattleDataContext::GetHeroLevel()
{
return std::max(hero_lv_, 1);
}