Shtille's blog A development blog

ESO DoTs comparison program. Part 2

Check the previous article to recall.

Test program for dots comparison

Program code

Skill names you can check at ESO skillbook.

#include <string>
#include <iostream>
#include <memory>
#include <list>

class Skill {
public:
	Skill(const std::string& name, double base_damage, double duration)
	: name_(name)
	, base_damage_(base_damage)
	, duration_(duration)
	{
	}
	virtual ~Skill() = default;
	virtual double GetDamage() const
	{
		return base_damage_;
	}
	virtual double GetDuration() const
	{
		return duration_;
	}
	double GetDps() const
	{
		return GetDamage() / GetDuration();
	}
	const std::string& GetName() const
	{
		return name_;
	}
protected:
	std::string name_;
	double base_damage_;
	double duration_;
};

class InstantSkill : public Skill {
public:
	InstantSkill(const std::string& name, double base_damage)
	: Skill(name, base_damage, 1.)
	{
	}
};

class LastingSkill : public Skill {
public:
	LastingSkill(
		const std::string& name,
		double base_damage, 
		double damage_tick, 
		double time_tick,
		double damage_over_duration,
		double duration,
		double prepare_time = 0.)
	: Skill(name, base_damage, duration)
	, damage_tick_(damage_tick)
	, time_tick_(time_tick)
	, damage_over_duration_(damage_over_duration)
	, prepare_time_(prepare_time)
	{
	}
	virtual double GetDamage() const
	{
		return base_damage_ 
			+ (damage_tick_ / time_tick_) * duration_ 
			+ damage_over_duration_;
	}
	virtual double GetDuration() const
	{
		return duration_ + prepare_time_;
	}
protected:
	double damage_tick_;
	double time_tick_;
	double damage_over_duration_;
	double prepare_time_;
};

// ---- Skills definition ----

class BitingJabs final : public InstantSkill {
public:
	BitingJabs()
	: InstantSkill("Biting Jabs", 4276.*3.)
	{}
};

class DeadlyCloak final : public LastingSkill {
public:
	DeadlyCloak()
	: LastingSkill("Deadly Cloak", 0., 2505., 2., 0., 20.)
	{}
};

class BlazingSpear final : public LastingSkill {
public:
	BlazingSpear()
	: LastingSkill("Blazing Spear", 9530., 803., 1., 0., 10.)
	{}
};

class BarbedTrap final : public LastingSkill {
public:
	BarbedTrap()
	: LastingSkill("Barbed Trap", 5348., 0., 1., 17280., 20., 1.5)
	{}
};

class SolarBarrage final : public LastingSkill {
public:
	SolarBarrage()
	: LastingSkill("Solar Barrage", 0., 1865., 2., 0., 22.)
	{}
};

class VampiresBane final : public LastingSkill {
public:
	VampiresBane()
	: LastingSkill("Vampire's Bane", 4731., 0., 1., 25424., 32.)
	{}
};

class RapidStrikes final : public InstantSkill {
public:
	RapidStrikes()
	: InstantSkill("Rapid Strikes", 3207.*4.3)
	{}
};

class RendingSlashes final : public LastingSkill {
public:
	RendingSlashes()
	: LastingSkill("Rending Slashes", 2838., 0., 1., 15390., 20.)
	{}
};

class RitualOfRetribution final : public LastingSkill {
public:
	RitualOfRetribution()
	: LastingSkill("Ritual of Retribution", 0., 1926., 2., 0., 20.)
	, damage_increase_(0.12)
	{}
	virtual double GetDamage() const
	{
		double dps_increase = 0.5 * (damage_tick_ / time_tick_) 
			* damage_increase_ * (duration_ / time_tick_ - 1.);
		return base_damage_ 
			+ ((damage_tick_ / time_tick_ + dps_increase) * duration_) 
			+ damage_over_duration_;
	}
private:
	double damage_increase_;
};

class Degeneration final : public LastingSkill {
public:
	Degeneration()
	: LastingSkill("Degeneration", 0., 0., 1., 24618., 24.)
	{}
};

class ConsumingTrap final : public LastingSkill {
public:
	ConsumingTrap()
	: LastingSkill("Consuming Trap", 0., 0., 1., 20515., 20.)
	{}
};

class Stampede final : public LastingSkill {
public:
	Stampede()
	: LastingSkill("Stampede", 5677., 1413., 1., 0., 15.)
	{}
};

class Carve final : public LastingSkill {
public:
	Carve()
	: LastingSkill("Carve", 7097., 0., 1., 12708., 12.)
	{}
};

// ---- End of skills definition ----

/**
 * Function compares skill sets (1,2) and (1,3).
 * @param[in] skill1 		The base skill (spammable).
 * @param[in] skill2 		The skill to test from skillset (1,2).
 * @param[in] skill3 		The skill to test from skillset (1,3).
 * @param[in] print 		Whether need to print the result.
 * @return Returns true if skillset (1,3) is better than (1,2), and false otherwise.
 */
bool CompareSkillSets(const Skill* skill1, const Skill* skill2, 
	const Skill* skill3, bool print)
{
	// Define variables
	double T1 = skill1->GetDuration();
	double T2 = skill2->GetDuration();
	double T3 = skill3->GetDuration();
	double R1 = skill1->GetDps();
	double R2 = skill2->GetDps();
	double R3 = skill3->GetDps();
	bool result = (R3-R2)+((T3-T2)*(R1*T1)/(T2*T3)) > 0.;
	if (print)
	{
		const Skill *first, *second;
		if (result)
			second = skill2, first = skill3;
		else
			first = skill2, second = skill3;
		std::cout << "skill " << first->GetName() << 
			" is better than " << second->GetName() << std::endl;
	}
	return result;
}

class ListComparator {
public:
	ListComparator(const Skill * spammable)
	: spammable_(spammable)
	{}

	bool operator()(const std::shared_ptr<Skill>& s1, const std::shared_ptr<Skill>& s2)
	{
		// Make descending order
		return !CompareSkillSets(spammable_, s1.get(), s2.get(), false);
	}

private:
	const Skill * spammable_;
};

int main(int argc, char const *argv[])
{
	auto spammable = std::make_unique<BitingJabs>();
	// Declare list of skills
	std::list< std::shared_ptr<Skill> > list = {
		std::make_shared<DeadlyCloak>(),
		std::make_shared<BlazingSpear>(),
		std::make_shared<BarbedTrap>(),
		std::make_shared<SolarBarrage>(),
		std::make_shared<VampiresBane>(),
		std::make_shared<RendingSlashes>(),
		std::make_shared<RitualOfRetribution>(),
		std::make_shared<Degeneration>(),
		std::make_shared<ConsumingTrap>(),
		std::make_shared<Stampede>(),
		std::make_shared<Carve>()
	};
	// Declare comparator
	ListComparator comparator(spammable.get());
	list.sort(comparator);
	// Print results
	std::cout << spammable->GetName();
	for (auto& skill_ptr : list)
	{
		std::cout << " > " << skill_ptr->GetName();
	}
	std::cout << std::endl;
	return 0;
}

Program output

Single line output has been divided by several lines.

Biting Jabs > Stampede > Ritual of Retribution > Deadly Cloak > Carve > 
Vampire's Bane > Degeneration > Blazing Spear > Barbed Trap > 
Consuming Trap > Solar Barrage > Rending Slashes

Conclusion

It’s funny that skill with lower DPS Vampire’s Bane has more outcome than Blazing Spear with higher DPS.

Improvements

  • Add additional skills.
  • Try different base skill (spammable) and compare results.

Skills to add

  • Power of the Light
  • Radiant Oppression ?
  • Lethal Arrow (bow spam)
  • Endless Hail
  • Acid Spray
  • Poison Injection
  • Dizzying Swing (2h spam)
  • Scalding Rune
  • Crushing Weapon (psijic)
  • Shadow Silk
  • Mystic Orb