1043 lines
32 KiB
C++
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);
|
|
}
|