Skip to content

Commit

Permalink
Roll glancing blow in range instead of static modifier.
Browse files Browse the repository at this point in the history
Low end:
1.3 - 0.05 * (t_defense - w_skill) capped at 0.91 max and 0.55 low.

High end:
1.2 - 0.03 * (t_defense - w_skill) capped at 0.99 max and 0.75 low.

Based on discussion in magey/classic-warrior#5

Note that low end cap (0.55 and 0.75) is *not* discussed but is an
implementation detail.
  • Loading branch information
timhul committed May 31, 2019
1 parent 283c5c6 commit 9f37a32
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 94 deletions.
2 changes: 2 additions & 0 deletions ClassicSim.pro
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ SOURCES += main.cpp \
Equipment/EquipmentDb/ItemFileReader.cpp \
Equipment/EquipmentDb/WeaponFileReader.cpp \
Equipment/Item/Weapon.cpp \
Test/TestCombatRoll.cpp \
Test/Warrior/TestWarrior.cpp \
Test/Warrior/Spells/TestExecute.cpp \
Test/TestSpell.cpp \
Expand Down Expand Up @@ -519,6 +520,7 @@ HEADERS += \
Equipment/EquipmentDb/ItemFileReader.h \
Equipment/EquipmentDb/WeaponFileReader.h \
Equipment/Item/Weapon.h \
Test/TestCombatRoll.h \
Test/Warrior/TestWarrior.h \
Test/Warrior/Spells/TestExecute.h \
Test/TestSpell.h \
Expand Down
12 changes: 11 additions & 1 deletion CombatRoll/CombatRoll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ CombatRoll::CombatRoll(Character *pchar):
pchar(pchar),
target(pchar->get_target()),
random(new Random(0, 9999)),
glance_roll(new Random(0, 9999)),
mechanics(new Mechanics(target)) {
}

CombatRoll::~CombatRoll() {
delete random;
delete glance_roll;

drop_tables();

Expand Down Expand Up @@ -226,7 +228,15 @@ double CombatRoll::get_yellow_miss_chance(const int wpn_skill) {
}

double CombatRoll::get_glancing_blow_dmg_penalty(const int wpn_skill) {
return mechanics->get_glancing_blow_dmg_penalty(wpn_skill);
const double min = mechanics->get_glancing_blow_dmg_penalty_min(pchar->get_clvl(), wpn_skill);
const double max = mechanics->get_glancing_blow_dmg_penalty_max(pchar->get_clvl(), wpn_skill);

const unsigned min_range = static_cast<unsigned>(round(min * 10000));
const unsigned max_range = static_cast<unsigned>(round(max * 10000));

glance_roll->set_new_range(min_range, max_range);

return static_cast<double>(glance_roll->get_roll()) / 10000;
}

void CombatRoll::update_melee_miss_chance() {
Expand Down
3 changes: 2 additions & 1 deletion CombatRoll/CombatRoll.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class CombatRoll {

double get_white_miss_chance(const int);
double get_yellow_miss_chance(const int wpn_skill);
double get_glancing_blow_dmg_penalty(const int);
double get_glancing_blow_dmg_penalty(const int wpn_skill);

void update_melee_miss_chance();
void update_ranged_miss_chance();
Expand All @@ -60,6 +60,7 @@ class CombatRoll {
Character* pchar;
Target* target;
Random* random;
Random* glance_roll;
Mechanics* mechanics;

QMap<int, MeleeWhiteHitTable*> melee_white_tables;
Expand Down
64 changes: 25 additions & 39 deletions Mechanics/Mechanics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,44 +73,34 @@ double Mechanics::get_block_chance() const {
return 0.0;
}

double Mechanics::get_glancing_blow_dmg_penalty(const int wpn_skill) const {
const int delta = target->get_defense() - wpn_skill;
double Mechanics::get_glancing_blow_dmg_penalty_min(const int clvl, const int wpn_skill) const {
const int level_diff = target->get_lvl() - static_cast<int>(clvl);
if (level_diff < 1)
return 1.0;

const double glance_max_range_penalty = 1.3 - 0.05 * (target->get_defense() - wpn_skill);

if (delta < 1)
if (glance_max_range_penalty < 0.55)
return 0.55;
if (glance_max_range_penalty > 0.91)
return 0.91;

return glance_max_range_penalty;
}

double Mechanics::get_glancing_blow_dmg_penalty_max(const int clvl, const int wpn_skill) const {
const int level_diff = target->get_lvl() - static_cast<int>(clvl);
if (level_diff < 1)
return 1.0;

switch (delta) {
case 1:
return 0.9926;
case 2:
return 0.984;
case 3:
return 0.9742;
case 4:
return 0.9629;
case 5:
return 0.95;
case 6:
return 0.9351;
case 7:
return 0.918;
case 8:
return 0.8984;
case 9:
return 0.8759;
case 10:
return 0.85;
case 11:
return 0.8203;
case 12:
return 0.786;
case 13:
return 0.7469;
case 14:
return 0.7018;
default:
return 0.65;
}
const double glance_max_range_penalty = 1.2 - 0.03 * (target->get_defense() - wpn_skill);

if (glance_max_range_penalty < 0.75)
return 0.75;
if (glance_max_range_penalty > 0.99)
return 0.99;

return glance_max_range_penalty;
}

int Mechanics::get_boss_base_armor() {
Expand All @@ -121,10 +111,6 @@ double Mechanics::get_reduction_from_armor(const int armor, const int clvl) {
return armor / (armor + 400 + 85 * (clvl + 4.5 * (clvl - 60)));
}

double Mechanics::get_linear_glancing_blow_dmg_penalty(const int wpn_skill) const {
return std::max(0.7, std::min(1.0, 1.0 - (target->get_defense() - wpn_skill - 5) * 0.03));
}

double Mechanics::get_melee_crit_suppression(const unsigned clvl) const {
const int level_diff = target->get_lvl() - static_cast<int>(clvl);

Expand Down
4 changes: 2 additions & 2 deletions Mechanics/Mechanics.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class Mechanics {
double get_parry_chance(const int wpn_skill) const;
double get_block_chance() const;

double get_glancing_blow_dmg_penalty(const int wpn_skill) const;
double get_linear_glancing_blow_dmg_penalty(const int wpn_skill) const;
double get_glancing_blow_dmg_penalty_min(const int clvl, const int wpn_skill) const;
double get_glancing_blow_dmg_penalty_max(const int clvl, const int wpn_skill) const;

double get_melee_crit_suppression(const unsigned clvl) const;

Expand Down
16 changes: 8 additions & 8 deletions Test/Paladin/Spells/TestMainhandAttackPaladin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ void TestMainhandAttackPaladin::test_glancing_damage_300_wpn_skill() {
when_mh_attack_is_performed();

// [Damage] = (base_dmg + (wpn_speed * AP / 14)) * glancing_dmg_modifier
// [186] = (100 + (2.6 * 1000 / 14)) * 0.65
then_damage_dealt_is(186);
// [157 - 214] = (100 + (2.6 * 1000 / 14)) * [0.55 - 0.75]
then_damage_dealt_is_in_range(157, 214);
}

void TestMainhandAttackPaladin::test_glancing_damage_305_wpn_skill() {
Expand All @@ -152,8 +152,8 @@ void TestMainhandAttackPaladin::test_glancing_damage_305_wpn_skill() {
when_mh_attack_is_performed();

// [Damage] = (base_dmg + (wpn_speed * AP / 14)) * glancing_dmg_modifier
// [243] = (100 + (2.6 * 1000 / 14)) * 0.85
then_damage_dealt_is(243);
// [229 - 257] = (100 + (2.6 * 1000 / 14)) * [0.8 - 0.9]
then_damage_dealt_is_in_range(229, 257);
}

void TestMainhandAttackPaladin::test_glancing_damage_310_wpn_skill() {
Expand All @@ -167,8 +167,8 @@ void TestMainhandAttackPaladin::test_glancing_damage_310_wpn_skill() {
when_mh_attack_is_performed();

// [Damage] = (base_dmg + (wpn_speed * AP / 14)) * glancing_dmg_modifier
// [271] = (100 + (2.6 * 1000 / 14)) * 0.9
then_damage_dealt_is(271);
// [260 - 283] = (100 + (2.6 * 1000 / 14)) * [0.91 - 0.99]
then_damage_dealt_is_in_range(260, 283);
}

void TestMainhandAttackPaladin::test_glancing_damage_315_wpn_skill() {
Expand All @@ -182,8 +182,8 @@ void TestMainhandAttackPaladin::test_glancing_damage_315_wpn_skill() {
when_mh_attack_is_performed();

// [Damage] = (base_dmg + (wpn_speed * AP / 14)) * glancing_dmg_modifier
// [143] = (100 + (2.6 * 1000 / 14)) * 1.0
then_damage_dealt_is(286);
// [260 - 283] = (100 + (2.6 * 1000 / 14)) * [0.91 - 0.99]
then_damage_dealt_is_in_range(260, 283);
}

void TestMainhandAttackPaladin::test_mid_swing_haste_increase_updates_attack_speed() {
Expand Down
2 changes: 2 additions & 0 deletions Test/Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "Test/Target/TestTarget.h"
#include "TestAttackTables.h"
#include "TestCharacterStats.h"
#include "TestCombatRoll.h"
#include "TestConditionVariableBuiltin.h"
#include "TestFelstrikerProc.h"
#include "TestHunter.h"
Expand Down Expand Up @@ -70,6 +71,7 @@ void Test::test_all() {
test_queue();

TestMechanics().test_all();
TestCombatRoll(equipment_db).test_all();
TestTarget().test_all();
TestAttackTables(equipment_db).test_all();
TestCharacterStats(equipment_db).test_all();
Expand Down
46 changes: 46 additions & 0 deletions Test/TestCombatRoll.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "TestCombatRoll.h"

#include <QDebug>

#include "CombatRoll.h"
#include "Target.h"
#include "Orc.h"
#include "Warrior.h"

TestCombatRoll::TestCombatRoll(EquipmentDb* equipment_db) :
equipment_db(equipment_db)
{}

void TestCombatRoll::test_all() {
qDebug() << "TestCombatRoll";
test_glancing_penalties();
}

void TestCombatRoll::test_glancing_penalties() {
auto* race = new Orc();
auto* pchar = new Warrior(race, equipment_db, nullptr);
auto* roll = pchar->get_combat_roll();

for (int i = 0; i < 1000; ++i) {
const double glance_penalty = roll->get_glancing_blow_dmg_penalty(300);
assert(glance_penalty > 0.54999 && glance_penalty < 0.75001);
}

for (int i = 0; i < 1000; ++i) {
const double glance_penalty = roll->get_glancing_blow_dmg_penalty(305);
assert(glance_penalty > 0.7999 && glance_penalty < 0.9001);
}

for (int i = 0; i < 1000; ++i) {
const double glance_penalty = roll->get_glancing_blow_dmg_penalty(310);
assert(glance_penalty > 0.90999 && glance_penalty < 0.99001);
}

for (int i = 0; i < 1000; ++i) {
const double glance_penalty = roll->get_glancing_blow_dmg_penalty(315);
assert(glance_penalty > 0.90999 && glance_penalty < 0.99001);
}

delete pchar;
delete race;
}
17 changes: 17 additions & 0 deletions Test/TestCombatRoll.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "TestUtils.h"

class EquipmentDb;

class TestCombatRoll : public TestUtils {
public:
TestCombatRoll(EquipmentDb* equipment_db);

void test_all();

private:
EquipmentDb* equipment_db;

void test_glancing_penalties();
};
40 changes: 15 additions & 25 deletions Test/TestMechanics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ void TestMechanics::test_all() {
test_dodge_from_wpn_skill_diff();
test_dw_white_miss();
test_glancing_blow_rate();
test_glancing_dmg_penalty_linear();
test_glancing_dmg_penalty_exponential();
test_glancing_dmg_penalty();
test_physical_crit_suppression_from_target_level();

test_full_resistance_chance();
Expand Down Expand Up @@ -74,32 +73,23 @@ void TestMechanics::test_glancing_blow_rate() {
delete target;
}

void TestMechanics::test_glancing_dmg_penalty_linear() {
void TestMechanics::test_glancing_dmg_penalty() {
auto* target = new Target(63);
auto* mechanics = new Mechanics(target);

assert(almost_equal(0.7, mechanics->get_linear_glancing_blow_dmg_penalty(5)));

assert(almost_equal(0.7, mechanics->get_linear_glancing_blow_dmg_penalty(300)));
assert(almost_equal(0.85, mechanics->get_linear_glancing_blow_dmg_penalty(305)));
assert(almost_equal(1.0, mechanics->get_linear_glancing_blow_dmg_penalty(310)));
assert(almost_equal(1.0, mechanics->get_linear_glancing_blow_dmg_penalty(10000)));

delete mechanics;
delete target;
}

void TestMechanics::test_glancing_dmg_penalty_exponential() {
auto* target = new Target(63);
auto* mechanics = new Mechanics(target);

assert(almost_equal(0.65, mechanics->get_glancing_blow_dmg_penalty(5)));

assert(almost_equal(0.65, mechanics->get_glancing_blow_dmg_penalty(300)));
assert(almost_equal(0.85, mechanics->get_glancing_blow_dmg_penalty(305)));
assert(almost_equal(0.95, mechanics->get_glancing_blow_dmg_penalty(310)));
assert(almost_equal(1.0, mechanics->get_glancing_blow_dmg_penalty(315)));
assert(almost_equal(1.0, mechanics->get_glancing_blow_dmg_penalty(10000)));
assert(almost_equal(0.55, mechanics->get_glancing_blow_dmg_penalty_min(60, 5)));
assert(almost_equal(0.55, mechanics->get_glancing_blow_dmg_penalty_min(60, 300)));
assert(almost_equal(0.80, mechanics->get_glancing_blow_dmg_penalty_min(60, 305)));
assert(almost_equal(0.91, mechanics->get_glancing_blow_dmg_penalty_min(60, 310)));
assert(almost_equal(0.91, mechanics->get_glancing_blow_dmg_penalty_min(60, 315)));
assert(almost_equal(0.91, mechanics->get_glancing_blow_dmg_penalty_min(60, 10000)));

assert(almost_equal(0.75, mechanics->get_glancing_blow_dmg_penalty_max(60, 5)));
assert(almost_equal(0.75, mechanics->get_glancing_blow_dmg_penalty_max(60, 300)));
assert(almost_equal(0.90, mechanics->get_glancing_blow_dmg_penalty_max(60, 305)));
assert(almost_equal(0.99, mechanics->get_glancing_blow_dmg_penalty_max(60, 310)));
assert(almost_equal(0.99, mechanics->get_glancing_blow_dmg_penalty_max(60, 315)));
assert(almost_equal(0.99, mechanics->get_glancing_blow_dmg_penalty_max(60, 10000)));

delete mechanics;
delete target;
Expand Down
3 changes: 1 addition & 2 deletions Test/TestMechanics.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ class TestMechanics : public TestUtils {

private:
void test_glancing_blow_rate();
void test_glancing_dmg_penalty_linear();
void test_glancing_dmg_penalty_exponential();
void test_glancing_dmg_penalty();
void test_dw_white_miss();
void test_dodge_from_wpn_skill_diff();
void test_physical_crit_suppression_from_target_level();
Expand Down
16 changes: 8 additions & 8 deletions Test/Warrior/Spells/TestMainhandAttackWarrior.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ void TestMainhandAttackWarrior::test_glancing_damage_300_wpn_skill() {
when_mh_attack_is_performed();

// [Damage] = (base_dmg + (wpn_speed * AP / 14)) * glancing_dmg_modifier
// [186] = (100 + (2.6 * 1000 / 14)) * 0.65
then_damage_dealt_is(186);
// [157 - 214] = (100 + (2.6 * 1000 / 14)) * [0.55 - 0.75]
then_damage_dealt_is_in_range(157, 214);
}

void TestMainhandAttackWarrior::test_glancing_damage_305_wpn_skill() {
Expand All @@ -169,8 +169,8 @@ void TestMainhandAttackWarrior::test_glancing_damage_305_wpn_skill() {
when_mh_attack_is_performed();

// [Damage] = (base_dmg + (wpn_speed * AP / 14)) * glancing_dmg_modifier
// [121] = (100 + (2.6 * 1000 / 14)) * 0.85
then_damage_dealt_is(243);
// [229 - 257] = (100 + (2.6 * 1000 / 14)) * [0.8 - 0.9]
then_damage_dealt_is_in_range(229, 257);
}

void TestMainhandAttackWarrior::test_glancing_damage_310_wpn_skill() {
Expand All @@ -185,8 +185,8 @@ void TestMainhandAttackWarrior::test_glancing_damage_310_wpn_skill() {
when_mh_attack_is_performed();

// [Damage] = (base_dmg + (wpn_speed * AP / 14)) * glancing_dmg_modifier
// [143] = (100 + (2.6 * 1000 / 14)) * 0.95
then_damage_dealt_is(271);
// [260 - 283] = (100 + (2.6 * 1000 / 14)) * [0.91 - 0.99]
then_damage_dealt_is_in_range(260, 283);
}

void TestMainhandAttackWarrior::test_glancing_damage_315_wpn_skill() {
Expand All @@ -201,8 +201,8 @@ void TestMainhandAttackWarrior::test_glancing_damage_315_wpn_skill() {
when_mh_attack_is_performed();

// [Damage] = (base_dmg + (wpn_speed * AP / 14)) * glancing_dmg_modifier
// [143] = (100 + (2.6 * 1000 / 14)) * 1.0
then_damage_dealt_is(286);
// [260 - 283] = (100 + (2.6 * 1000 / 14)) * [0.91 - 0.99]
then_damage_dealt_is_in_range(260, 283);
}

void TestMainhandAttackWarrior::test_mid_swing_haste_increase_updates_attack_speed() {
Expand Down
Loading

0 comments on commit 9f37a32

Please sign in to comment.