Skip to content

Commit

Permalink
add possibility to optimize damage & fix unique trophy
Browse files Browse the repository at this point in the history
  • Loading branch information
remi-dupre committed Nov 9, 2019
1 parent 6f51261 commit e8b65c7
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 45 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ install:
before_script:
- rustup component add clippy
- rustup component add rustfmt --toolchain nightly
- if [ ! -d data/sets.json ]; then ./download_data.sh; fi

script:
- cargo check
- cargo clippy -- -D warnings
- cargo +nightly fmt --all -- --check

before_deploy:
- if [ ! -d data/sets.json ]; then ./download_data.sh; fi
- cargo build --release
- mkdir dofus-generate-stuff
&& cp target/release/dofus-generate-stuff dofus-generate-stuff
Expand All @@ -31,7 +31,7 @@ deploy:
provider: releases
api_key: $GITHUB_TOKEN
file:
- target/release/dofus-generate-stuff
- dofus-generate-stuff.tar.gz
skip_cleanup: true
on:
tags: true
Expand Down
28 changes: 28 additions & 0 deletions examples/ambush.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"level": 200,
"target": [
[{"Carac": "AP"}, 11],
[{"Carac": "MP"}, 6],
["Resiliance", 4000],
[
{
"MeanDamage": {
"critical": 5,
"effect": [
{"Hit": {"element": "Air", "bounds": [10, 12]}},
{"Hit": {"element": "Earth", "bounds": [10, 12]}},
{"Hit": {"element": "Fire", "bounds": [10, 12]}},
{"Hit": {"element": "Water", "bounds": [10, 12]}}
],
"critical_effect": [
{"Hit": {"element": "Air", "bounds": [12, 14]}},
{"Hit": {"element": "Earth", "bounds": [12, 14]}},
{"Hit": {"element": "Fire", "bounds": [12, 14]}},
{"Hit": {"element": "Water", "bounds": [12, 14]}}
]
}
},
3000
]
]
}
106 changes: 93 additions & 13 deletions src/character.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use std::convert::TryInto;
use serde::Deserialize;

use crate::dofapi::{
CaracKind, Condition, ConditionAtom, Element, Equipement, ItemType, Set,
CaracKind, Condition, ConditionAtom, Effect, Element, Equipement,
ItemType, Set, SpellEffects,
};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -548,15 +549,10 @@ impl RawCaracs<'_> {
pub fn eval(&self, value: &RawCaracsValue) -> f64 {
match value {
RawCaracsValue::Carac(carac) => self.get_carac(carac) as f64,
RawCaracsValue::PowStats(elem) => match elem {
Element::Neutral => {
self.eval(&RawCaracsValue::PowStats(Element::Earth))
}
_ => {
self.get_carac(&CaracKind::Stats(*elem)) as f64
+ self.get_carac(&CaracKind::Power) as f64
}
},
RawCaracsValue::PowStats(elem) => {
self.get_carac(&CaracKind::Stats(elem.effective_stat())) as f64
+ self.get_carac(&CaracKind::Power) as f64
}
RawCaracsValue::MeanExtraDamage(elem) => {
self.mean_extra_damage(*elem)
}
Expand All @@ -576,6 +572,9 @@ impl RawCaracs<'_> {
(square_diffs.sum::<f64>() / 5.).sqrt()
}
RawCaracsValue::Resiliance => self.resiliance(),
RawCaracsValue::MeanDamage(effects) => {
self.mean_weapon_damage(effects, true)
}
}
}

Expand All @@ -602,11 +601,88 @@ impl RawCaracs<'_> {
}

pub fn mean_extra_damage(&self, element: Element) -> f64 {
let base_dmg = self.get_carac(&CaracKind::Damage(element)) as f64;
let critical = self.get_carac(&CaracKind::Critical) as f64;
let crit_dmg = self.get_carac(&CaracKind::CriticalDamage) as f64;
let base_dmg: f64 = self.get_carac(&CaracKind::Damage(element)).into();
let critical: f64 = (10 + self.get_carac(&CaracKind::Critical)).into();
let crit_dmg: f64 = self.get_carac(&CaracKind::CriticalDamage).into();
base_dmg + (crit_dmg * critical / 100.)
}

pub fn mean_effect_damage(
&self,
effect: &Effect,
is_crit: bool,
is_spell: bool,
is_dist: bool,
) -> f64 {
match effect {
Effect::Hit {
element, bounds, ..
} => {
let mut damage: f64 = self
.eval(&RawCaracsValue::PowStats(element.effective_stat()))
* (f64::from(*bounds.start()) + f64::from(*bounds.end()))
/ 200.;

damage +=
f64::from(self.get_carac(&CaracKind::Damage(*element)));

if is_crit {
damage +=
f64::from(self.get_carac(&CaracKind::CriticalDamage));
}

if is_spell {
damage *= 1.
+ f64::from(
self.get_carac(&CaracKind::PerSpellDamage),
) / 100.;
} else {
damage *= 1.
+ f64::from(
self.get_carac(&CaracKind::PerWeaponDamage),
) / 100.;
}

if is_dist {
damage *= 1.
+ f64::from(
self.get_carac(&CaracKind::PerRangedDamage),
) / 100.
} else {
damage *= 1.
+ f64::from(self.get_carac(&CaracKind::PerMeleeDamage))
/ 100.
}

damage
}
}
}

pub fn mean_weapon_damage(
&self,
effects: &SpellEffects,
is_dist: bool,
) -> f64 {
let mean_dmg_nocrit: f64 = effects
.effect
.iter()
.map(|effect| {
self.mean_effect_damage(effect, false, false, is_dist)
})
.sum();
let mean_dmg_crit: f64 = effects
.critical_effect
.iter()
.map(|effect| {
self.mean_effect_damage(effect, true, false, is_dist)
})
.sum();
let crit: f64 = f64::from(
i16::from(effects.critical) + self.get_carac(&CaracKind::Critical),
) / 100.;
(1. - crit) * mean_dmg_nocrit + crit * mean_dmg_crit
}
}

// ____ ______ __ _
Expand All @@ -622,6 +698,7 @@ pub enum RawCaracsValue {
Carac(CaracKind),
PowStats(Element),
MeanExtraDamage(Element),
MeanDamage(SpellEffects),
PerResVariance,
Resiliance,
}
Expand All @@ -644,6 +721,9 @@ impl RawCaracsValue {
.smithmage_weight()
.unwrap()
}
RawCaracsValue::MeanDamage(_) => {
CaracKind::Vitality.smithmage_weight().unwrap()
}
})
}

Expand Down
10 changes: 6 additions & 4 deletions src/dofapi/carac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,17 +233,19 @@ impl CaracLines {
// Check if all stats of `other` are covered by this item.
self.as_map()
.get(kind)
.map(|self_bounds| self_bounds.start() >= other_bounds.end())
.unwrap_or(*other_bounds.end() <= 0)
.map(|self_bounds| self_bounds.start())
.unwrap_or(&0)
>= other_bounds.end()
}) && self.as_map().iter().all(|(kind, self_bounds)| {
// Check if all stats of this item are covered by `other`.
// This is required since there may be some negative values in this
// item that are not in `other`.
other
.as_map()
.get(kind)
.map(|other_bounds| self_bounds.start() >= other_bounds.end())
.unwrap_or(*self_bounds.start() >= 0)
.map(|other_bounds| other_bounds.end())
.unwrap_or(&0)
<= self_bounds.start()
})
}
}
Expand Down
44 changes: 39 additions & 5 deletions src/dofapi/effect.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use serde::Deserialize;
use std::ops::RangeInclusive;

// _____ _ _
// | ____| | ___ _ __ ___ ___ _ __ | |_
Expand All @@ -16,6 +17,16 @@ pub enum Element {
Neutral,
}

impl Element {
/// Return the element that boosts the damages applied in this element.
pub fn effective_stat(&self) -> Element {
match self {
Self::Neutral => Self::Earth,
_ => *self,
}
}
}

// ____ _ _
// | _ \ __ _ _ __ ___ __ _ __ _ ___| | (_)_ __ ___
// | | | |/ _` | '_ ` _ \ / _` |/ _` |/ _ \ | | | '_ \ / _ \
Expand All @@ -24,9 +35,32 @@ pub enum Element {
// |___/

#[derive(Debug, Deserialize)]
pub struct DamageLine {
pub element: Element,
pub min: i64,
pub max: i64,
pub lifesteal: bool,
pub enum Effect {
Hit {
element: Element,
bounds: RangeInclusive<u8>,

#[serde(default = "default_spell_lifesteal")]
lifesteal: bool,
},
}

#[derive(Debug, Deserialize)]
pub struct SpellEffects {
pub effect: Vec<Effect>,

#[serde(default = "default_spell_critical")]
pub critical: u8,

#[serde(default)]
pub critical_effect: Vec<Effect>,
}

/// Default spell critical chances.
fn default_spell_critical() -> u8 {
5
}

fn default_spell_lifesteal() -> bool {
false
}
36 changes: 24 additions & 12 deletions src/dofapi/equipement.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::collections::HashSet;
use std::fmt;

use serde::{de, Deserialize, Deserializer};
Expand Down Expand Up @@ -123,18 +122,31 @@ pub fn fix_all_trophy(db: &mut [Equipement]) {
.for_each(|item| {
// A trophy is unique if no other trophy covers all its positive
// bonuses.
let is_unique = !trophy_list
let has_no_malus = item
.statistics
.as_map()
.iter()
.filter(|other| other.level == item.level)
.any(|other| {
let other_lines: HashSet<_> =
other.statistics.as_map().keys().collect();
item.statistics
.as_map()
.iter()
.filter(|(_kind, bounds)| *bounds.start() >= 0)
.all(|(kind, _bounds)| other_lines.contains(kind))
});
.all(|(_, bounds)| *bounds.start() >= 0);

let is_unique = has_no_malus
&& trophy_list
.iter()
.filter(|other| other._id != item._id)
.filter(|other| other.level == item.level)
.all(|other| {
item.statistics
.as_map()
.iter()
.filter(|(_kind, bounds)| *bounds.start() >= 0)
.any(|(kind, _bounds)| {
other
.statistics
.as_map()
.get(kind)
.map(|bounds| *bounds.end() < 0)
.unwrap_or(true)
})
});

// A trophy is strong if it is unique or better than another trophy
let is_strong = is_unique
Expand Down
2 changes: 1 addition & 1 deletion src/dofapi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod set;

pub use carac::{CaracKind, CaracLines};
pub use condition::{Condition, ConditionAtom};
pub use effect::{DamageLine, Element};
pub use effect::{Effect, Element, SpellEffects};
pub use equipement::{Equipement, ItemType};
pub use set::Set;

Expand Down
16 changes: 10 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ fn main() -> io::Result<()> {
.filter_map(|slot| slot.get_item())
.for_each(|item| println!(" {:^46} {}", item.name, item.url));
println!("------------------------------------------------");

let stats = &[
CaracKind::AP,
CaracKind::MP,
Expand Down Expand Up @@ -203,21 +202,26 @@ fn main() -> io::Result<()> {
CaracKind::PerResistance(Element::Water),
CaracKind::PerResistance(Element::Neutral),
];

let caracs = character.get_caracs();
for stat in stats {
println!(" {:35} {:>10}", stat, caracs.get_carac(stat));
}
println!("------------------------------------------------");
for (target, val) in input.target {
println!(
" - {:?}: {} / {}",
target,
character.get_caracs().eval(&target),
val
);
}
println!("------------------------------------------------");
println!("\nstats: {:?}", character.base_stats);
println!(
"conditions ({}): {:?}",
character.condition_overflow(&character.all_conditions()),
character.all_conditions()
);
println!(
"\nstats: {:?}",
caracs.eval(&character::RawCaracsValue::PerResVariance)
);
}
}

Expand Down
Loading

0 comments on commit e8b65c7

Please sign in to comment.