mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/combat-ratings' into 'master'
Tweaks to Combat Rating Calculation See merge request veloren/veloren!2051
This commit is contained in:
commit
8d9f63404e
@ -89,7 +89,7 @@ Is the client up to date?"#,
|
||||
"common.rand_appearance": "Random appearance",
|
||||
"common.rand_name": "Random name",
|
||||
|
||||
"common.stats.dps": "DPS",
|
||||
"common.stats.combat_rating": "CR",
|
||||
"common.stats.power": "Power",
|
||||
"common.stats.speed": "Speed",
|
||||
"common.stats.poise": "Poise",
|
||||
|
@ -30,7 +30,7 @@
|
||||
"hud.bag.combat_rating": "Combat Rating",
|
||||
"hud.bag.protection": "Protection",
|
||||
"hud.bag.combat_rating_desc": "Calculated from your\nequipment and health.",
|
||||
"hud.bag.protection": "Damage reduction through armor",
|
||||
"hud.bag.protection_desc": "Damage reduction through armor",
|
||||
},
|
||||
|
||||
|
||||
|
@ -87,7 +87,7 @@ Le client est-il à jour?"#,
|
||||
|
||||
"common.rand_appearance": "Apparence et nom aléatoire",
|
||||
|
||||
"common.stats.dps": "DPS",
|
||||
"common.stats.combat_rating": "CR",
|
||||
"common.stats.power": "Puissance",
|
||||
"common.stats.speed": "Vitesse",
|
||||
"common.stats.poise": "Impact",
|
||||
|
@ -6,13 +6,13 @@ use crate::{
|
||||
inventory::{
|
||||
item::{
|
||||
armor::Protection,
|
||||
tool::{Tool, ToolKind},
|
||||
Item, ItemKind, MaterialStatManifest,
|
||||
tool::{self, Tool, ToolKind},
|
||||
Item, ItemDesc, ItemKind, MaterialStatManifest,
|
||||
},
|
||||
slot::EquipSlot,
|
||||
},
|
||||
poise::PoiseChange,
|
||||
skills::{SkillGroupKind, SkillSet},
|
||||
skills::SkillGroupKind,
|
||||
Body, Combo, Energy, EnergyChange, EnergySource, Health, HealthChange, HealthSource,
|
||||
Inventory, Stats,
|
||||
},
|
||||
@ -721,21 +721,55 @@ pub fn get_weapons(inv: &Inventory) -> (Option<ToolKind>, Option<ToolKind>) {
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn offensive_rating(inv: &Inventory, skillset: &SkillSet, msm: &MaterialStatManifest) -> f32 {
|
||||
let active_damage =
|
||||
equipped_item_and_tool(inv, EquipSlot::Mainhand).map_or(0.0, |(item, tool)| {
|
||||
tool.base_power(msm, item.components())
|
||||
* tool.base_speed(msm, item.components())
|
||||
* (1.0 + 0.05 * skillset.earned_sp(SkillGroupKind::Weapon(tool.kind)) as f32)
|
||||
});
|
||||
let second_damage =
|
||||
equipped_item_and_tool(inv, EquipSlot::Offhand).map_or(0.0, |(item, tool)| {
|
||||
tool.base_power(msm, item.components())
|
||||
* tool.base_speed(msm, item.components())
|
||||
* (1.0 + 0.05 * skillset.earned_sp(SkillGroupKind::Weapon(tool.kind)) as f32)
|
||||
});
|
||||
active_damage.max(second_damage)
|
||||
pub fn weapon_rating<T: ItemDesc>(item: &T, msm: &MaterialStatManifest) -> f32 {
|
||||
const DAMAGE_WEIGHT: f32 = 2.0;
|
||||
const POISE_WEIGHT: f32 = 1.0;
|
||||
|
||||
if let ItemKind::Tool(tool) = item.kind() {
|
||||
let stats = tool::Stats::from((msm, item.components(), tool));
|
||||
|
||||
let damage_rating =
|
||||
stats.power * stats.speed * (1.0 + stats.crit_chance * (stats.crit_mult - 1.0));
|
||||
let poise_rating = stats.poise_strength * stats.speed;
|
||||
|
||||
(damage_rating * DAMAGE_WEIGHT + poise_rating * POISE_WEIGHT)
|
||||
/ (DAMAGE_WEIGHT + POISE_WEIGHT)
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
fn weapon_skills(inventory: &Inventory, stats: &Stats) -> f32 {
|
||||
let (mainhand, offhand) = get_weapons(inventory);
|
||||
let mainhand_skills = if let Some(tool) = mainhand {
|
||||
stats.skill_set.earned_sp(SkillGroupKind::Weapon(tool)) as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let offhand_skills = if let Some(tool) = offhand {
|
||||
stats.skill_set.earned_sp(SkillGroupKind::Weapon(tool)) as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
mainhand_skills.max(offhand_skills)
|
||||
}
|
||||
|
||||
fn get_weapon_rating(inventory: &Inventory, msm: &MaterialStatManifest) -> f32 {
|
||||
let mainhand_rating =
|
||||
if let Some((item, _)) = equipped_item_and_tool(inventory, EquipSlot::Mainhand) {
|
||||
weapon_rating(item, msm)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let offhand_rating =
|
||||
if let Some((item, _)) = equipped_item_and_tool(inventory, EquipSlot::Offhand) {
|
||||
weapon_rating(item, msm)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
mainhand_rating.max(offhand_rating)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@ -746,15 +780,28 @@ pub fn combat_rating(
|
||||
body: Body,
|
||||
msm: &MaterialStatManifest,
|
||||
) -> f32 {
|
||||
let defensive_weighting = 1.0;
|
||||
let offensive_weighting = 1.0;
|
||||
let defensive_rating = health.maximum() as f32
|
||||
/ (1.0 - Damage::compute_damage_reduction(Some(inventory), Some(stats))).max(0.00001)
|
||||
/ 100.0;
|
||||
let offensive_rating = offensive_rating(inventory, &stats.skill_set, msm).max(0.1)
|
||||
+ 0.05 * stats.skill_set.earned_sp(SkillGroupKind::General) as f32;
|
||||
let combined_rating = (offensive_rating * offensive_weighting
|
||||
+ defensive_rating * defensive_weighting)
|
||||
/ (offensive_weighting + defensive_weighting);
|
||||
const WEAPON_WEIGHT: f32 = 1.0;
|
||||
const HEALTH_WEIGHT: f32 = 1.0;
|
||||
const SKILLS_WEIGHT: f32 = 1.0;
|
||||
// Assumes a "standard" max health of 100
|
||||
let health_rating = health.base_max() as f32
|
||||
/ 100.0
|
||||
/ (1.0 - Damage::compute_damage_reduction(Some(inventory), Some(stats))).max(0.00001);
|
||||
|
||||
// Assumes a standard person has earned 20 skill points in the general skill
|
||||
// tree and 10 skill points for the weapon skill tree
|
||||
let skills_rating = (stats.skill_set.earned_sp(SkillGroupKind::General) as f32 / 20.0
|
||||
+ weapon_skills(inventory, stats) / 10.0)
|
||||
/ 2.0;
|
||||
|
||||
let weapon_rating = get_weapon_rating(inventory, msm);
|
||||
|
||||
let combined_rating = (health_rating * HEALTH_WEIGHT
|
||||
+ skills_rating * SKILLS_WEIGHT
|
||||
+ weapon_rating * WEAPON_WEIGHT)
|
||||
/ (HEALTH_WEIGHT + SKILLS_WEIGHT + WEAPON_WEIGHT);
|
||||
|
||||
// Body multiplier meant to account for an enemy being harder than equipment and
|
||||
// skills would account for. It should only not be 1.0 for non-humanoids
|
||||
combined_rating * body.combat_multiplier()
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use crate::{
|
||||
};
|
||||
use client::Client;
|
||||
use common::{
|
||||
combat,
|
||||
comp::item::{armor::Protection, Item, ItemDesc, ItemKind, MaterialStatManifest, Quality},
|
||||
trade::SitePrices,
|
||||
};
|
||||
@ -553,10 +554,10 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
let poise_str = tool.base_poise_strength(self.msm, item.components()) * 10.0;
|
||||
let crit_chance = tool.base_crit_chance(self.msm, item.components()) * 100.0;
|
||||
let crit_mult = tool.base_crit_mult(self.msm, item.components());
|
||||
let dps = power * speed;
|
||||
let combat_rating = combat::weapon_rating(&item, self.msm) * 10.0;
|
||||
|
||||
// DPS
|
||||
widget::Text::new(&format!("{:.1}", dps))
|
||||
// Combat Rating
|
||||
widget::Text::new(&format!("{:.1}", combat_rating))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
@ -566,7 +567,7 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
.right_from(state.ids.item_frame, H_PAD)
|
||||
.set(state.ids.main_stat, ui);
|
||||
|
||||
widget::Text::new(i18n.get("common.stats.dps"))
|
||||
widget::Text::new(i18n.get("common.stats.combat_rating"))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
@ -665,11 +666,12 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
);
|
||||
let crit_mult_diff =
|
||||
util::comparison(tool_stats.crit_mult, equipped_tool_stats.crit_mult);
|
||||
let equipped_dps =
|
||||
equipped_tool_stats.power * equipped_tool_stats.speed * 10.0;
|
||||
let diff_main_stat = util::comparison(dps, equipped_dps);
|
||||
let equipped_combat_rating =
|
||||
combat::weapon_rating(&equipped_item, self.msm) * 10.0;
|
||||
let diff_main_stat =
|
||||
util::comparison(combat_rating, equipped_combat_rating);
|
||||
|
||||
if equipped_dps - dps != 0.0 {
|
||||
if (equipped_combat_rating - combat_rating).abs() > f32::EPSILON {
|
||||
widget::Text::new(&diff_main_stat.0)
|
||||
.right_from(state.ids.main_stat_text, H_PAD)
|
||||
.graphics_for(id)
|
||||
@ -679,7 +681,7 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
.set(state.ids.diff_main_stat, ui);
|
||||
}
|
||||
|
||||
if diff.power != 0.0 {
|
||||
if diff.power.abs() > f32::EPSILON {
|
||||
widget::Text::new(&format!(
|
||||
"{} {:.1}",
|
||||
&power_diff.0,
|
||||
@ -693,7 +695,7 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
.color(power_diff.1)
|
||||
.set(state.ids.diffs[0], ui);
|
||||
}
|
||||
if diff.speed != 0.0 {
|
||||
if diff.speed.abs() > f32::EPSILON {
|
||||
widget::Text::new(&format!("{} {:.1}", &speed_diff.0, &diff.speed))
|
||||
.align_middle_y_of(state.ids.stats[1])
|
||||
.right_from(state.ids.stats[1], H_PAD)
|
||||
@ -703,7 +705,7 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
.color(speed_diff.1)
|
||||
.set(state.ids.diffs[1], ui);
|
||||
}
|
||||
if diff.poise_strength != 0.0 {
|
||||
if diff.poise_strength.abs() > f32::EPSILON {
|
||||
widget::Text::new(&format!(
|
||||
"{} {:.1}",
|
||||
&poise_strength_diff.0,
|
||||
@ -717,7 +719,7 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
.color(poise_strength_diff.1)
|
||||
.set(state.ids.diffs[2], ui);
|
||||
}
|
||||
if diff.crit_chance != 0.0 {
|
||||
if diff.crit_chance.abs() > f32::EPSILON {
|
||||
widget::Text::new(&format!(
|
||||
"{} {:.1}%",
|
||||
&crit_chance_diff.0,
|
||||
@ -731,7 +733,7 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
.color(crit_chance_diff.1)
|
||||
.set(state.ids.diffs[3], ui);
|
||||
}
|
||||
if diff.crit_mult != 0.0 {
|
||||
if diff.crit_mult.abs() > f32::EPSILON {
|
||||
widget::Text::new(&format!(
|
||||
"{} {:.1}",
|
||||
&crit_mult_diff.0, &diff.crit_mult
|
||||
|
Loading…
Reference in New Issue
Block a user