Login

russian armor

A corrected model for infantry DPS

5 Apr 2021, 18:23 PM
#1
avatar of Hannibal
Senior Moderator Badge

Posts: 3114 | Subs: 2

UPDATE 21.04.21
Merge with infantry power calculator

Downloadable here.

Contains:
1 .ipynb file with the script for interactive python
1 .csv file (weapon_report export for attribute editor)
1 .xlsx file to define squads

Needed: Interactive Python 3.X + numpy, pandas, math, plotly.express libraries

Changes:





Currently, the only source of DPS for small arms fire is Cruzz’ formula (also see Vipper’s guide), as well as coh2.serealia.ca which is an updated version that apparently uses Cruzz’ formula as well. However, no one knows where this formula came from.

When I tried to re-calculate these values on my own, I was unable to replicate the exact same values. Since this error could become quite large. I did some more digging only to find out that the formula does not match what I saw in-game.
Some time ago when I tested tank cannons, I found another probably game engine-related issue that increased the time between shots by 0.125 per used stat (I will call this 0.125 addition ‘correction time’ from now on), therefore I expected a similar issue with small arms. I then started iteratively modding and things turned out to be more complicated than that, but finally I can present a model that:

1. Matches the in-game time for shot cycles and
2. Based on that calculates the correct DPS of a given weapon.


I’ll spare you the lengthy details, in essence I had to test every stat separately to see how it behaves, changed it in a mod and then measured the time in-game by hand. If some of you wish to see the raw data, I can provide it but warning ahead it is quite convoluted. "Readability” was not an aim since I initially thought it would only be a quick notation sheet.
Additionally, one limitation is that I had to use "fixed" stats, meaning every stat was defined. The game however often uses randomization for some stats. Although I am fairly certain that I checked for all or at least most of this and my new model reflects this randomness, I cannot exclude with 100% certainty that this will lead to minor differences in the game and in my model. However, these differences will be minor, so I am confident to say that the new formula is better than the old one in any case.

The following spoiler defines a couple of “functions” that are necessary to understand the final formula:



Single fire weapons:


Stat overview:


The easiest way to calculate the DPS is to calculate the expected damage done and divide by the time for a complete shot cycle. Therefore, all variables that are randomly picked from an interval need to be taken as the mean between the interval borders. For brevity and visual clarity, I won’t note it down in the formula.

Expected damage:
Note ahead: Chance to hit and chance to penetrate are capped at 1. The braces are only there to group related stats and not needed for calculation

(Accuracy * target_RA) * (penetration / target_armor) * (reload_frequency + 1) * damage

It’s fairly straight forward: chance to hit times chance to pen times bullets in magazine times damage per bullet.

Cycle time:
(fire_aim_time + wind_up + wind_down + cooldown) * (reload_frequency + 1) - mean_CD + reload_duration

This means the model cycles through (fire_aim_time + wind_up + wind_down + cooldown) until the last bullet left in the magazine. For the last bullet, no cooldown is applied and the model directly enters the reload animation.
I have seen that the model also sometimes has intermediary animations (looking left and right, cowering etc. This does NOT affect the timings.



Burst fire weapons:


This is were things get tricky mostly because we get some additional stats.

Stat overview:


The reasoning is the same as before: Expected damage divided by the time needed.

Expected damage:
Chance to hit and chance to penetrate are capped at 1. The braces are only there to group related stats and not needed for calculation. I only have limited data on the ROF*burst_duration, but from what I saw this value is not rounded down. If a “half bullet” is calculated, there is either a random check of the bullet is given or not or it is carried over to the next cycle. I assume the latter, but not sure.

(Accuracy * target_RA) * (penetration / target_armor) * (burst_duration * ROF) * (reload_frequency + 1) * damage

Same as before. But since we have multiple bullets instead of one, we add another factor to calculate how many: ROF times burst_duration.


Cycle time:
(fire_aim_time + wind_up + wind_down + cooldown + burst_duration) * (reload_frequency + 1) - mean_CD + reload_duration

Same as before. We just add the burst_duration.



Further comments:
The old formula adds the ready_aim time. This is false. Ready_aim time defines the time to focus on a new enemy and is applied only ONCE at the beginning of the fight. It also subtracts the fire aim time. This is false too.


Aftermath
(I'll quickly add another paragraph to give some perspective)
So, what about all this. Overall this doesn't sound like a huge change, does it?
Depends on the weapon you look at. Literally all DPS profiles in coh2.serealia.ca are incorrect. Some values are still close to each other, others are not. For example, the Ranger M1A1 carbine is shows as having 10 DPS in serealia at range 0-4. My in-game tests however showed something closer to 8 (39-40 seconds needed to kill 4 Partisans with in total 320 HP at point blank which leads a DPS of 8-8,2. This leads to a difference of 20% in this rather extreme case. My formula calculates 8,207 which seems to be way closer to the in-game situation. In serealia, the Tommy Bren gun starts at 4,1 and ends at 6,9 DPS, my formula calculates 4,5 (+10%) and 6,95 (+0,1%) respectively. Or the Gren K98 goes from 5,99 to 2,26 DPS, while the new formula returns 5,27 (-12%) to 2,16 (-4%). We're currently in a state of the game where things are in general decently balanced, every move we make now can naturally only be a tiny step. If we want to make further changes, we need to get the correct numbers. I checked some few weapons in the game and my model is consistent with timings that I measured in game and some TTK data I gathered. I encourage everyone to do some measurements themselves and also report back what they got.



I’ll leave it at this for now, it is quite a wall of text already. I spent a lot of time on this, if anyone has doubts about my formula I would kindly ask to gather some data yourself. I will be all ears for discussion, but after countless cycles of changing stats and stopping times, I would like to have a break on this.
I hope this helps for the upcoming commander patch. Release version can be found here.



Hannibal out


5 Apr 2021, 18:57 PM
#2
avatar of Vipper

Posts: 13496 | Subs: 1

... I found another probably game engine-related issue that increased the time between shots by 0.125 per used stat...

nice work.

Yes the game use 1.25 tick and timers use that tick.
5 Apr 2021, 19:04 PM
#3
avatar of Hannibal
Senior Moderator Badge

Posts: 3114 | Subs: 2

jump backJump back to quoted post5 Apr 2021, 18:57 PMVipper

nice work.

Yes the game use 1.25 tick and timers use that tick.

Thank you very much.

I knew that, this is also what I suspected back in the tank gun tests and then termed "correction time". I thought the game needs to "wait" until the next tick when the previous part of the firing processed finished.
Things here are more complicated though. Some stats still use this correction time, others add a plain 0,125 seconds (so you can go from 0,4 to 0,525) and there will be no correction time at all. And in a third case nothing is applied. I don't know if the 64 bit update changed something, one would need to test tank guns again. But in the end it does not really matter that much. In the case of fire_aim time, this also differs between burst and single fire. Maybe my model that's not exactly what happens, but at least it is one way to describe the outcome.
5 Apr 2021, 19:09 PM
#4
avatar of ZeroZeroNi

Posts: 1563

Currently, the only source of DPS for small arms fire is Cruzz’ formula (also see Vipper’s guide), as well as coh2.serealia.ca which is an updated version that apparently uses Cruzz’ formula as well. However, no one knows where this formula came from.

When I tried to re-calculate these values on my own, I was unable to replicate the exact same values. Since this error could become quite large. I did some more digging only to find out that the formula does not match what I saw in-game.
Some time ago when I tested tank cannons, I found another probably game engine-related issue that increased the time between shots by 0.125 per used stat (I will call this 0.125 addition ‘correction time’ from now on), therefore I expected a similar issue with small arms. I then started iteratively modding and things turned out to be more complicated than that, but finally time I can present a model that:



I’ll spare you the lengthy details, in essence I had to test every stat separately to see how it behaves, changed it in a mod and then measured the time in-game by hand. If some of you wish to see the raw data, I can provide it but warning ahead it is quite convoluted. "Readability” was not an aim since I initially thought it would only be a quick notation sheet.
Additionally, one limitation is that I had to use "fixed" stats, meaning every stat was defined. The game however often uses randomization for some stats. Although I am fairly certain that I checked for all or at least most of this and my new model reflects this randomness, I cannot exclude with 100% certainty is that this will lead to minor differences in the game and in my model. However, these differences will be minor, so I am confident to say that the new formula is better than the old one in any case.

The following spoiler defines a couple of “functions” that are necessary to understand the final formula:



Single fire weapons:


Stat overview:


The easiest way to calculate the DPS is to calculate the expected damage done and divide by the time for a complete shot cycle. Therefore, all variables that are randomly picked from an interval need to be taken as the mean between the interval borders. For brevity and visual clarity, I won’t note it down in the formula.

Expected damage:
Note ahead: Accuracy and penetration are capped at 1. The braces are only there to group related stats and not needed for calculation


It’s fairly straight forward: chance to hit times chance to pen times bullets in magazine times damage per bullet.

Cycle time:

This means the model cycles through (fire_aim_time + wind_up + wind_down + cooldown) until the last bullet left in the magazine. For the last bullet, no cooldown is applied and the model directly enters the reload animation.
I have seen that the model also sometimes has intermediary animations (looking left and right, cowering etc. This does NOT affect the timings.



Burst fire weapons:


This is were things get tricky mostly because we get some additional stats.

Stat overview:


The reasoning is the same as before: Expected damage divided by the time needed.

Expected damage:
Accuracy and penetration are capped at 1. The braces are only there to group related stats and not needed for calculation. I only have limited data on the ROF*burst_duration, but from what I saw this value is not rounded down. If a “half bullet” is calculated, there is either a random check of the bullet is given or not or it is carried over to the next cycle. I assume the latter, but not sure.


Same as before. But since we have multiple bullets instead of one, we add another factor to calculate how many: ROF times burst_duration.


Cycle time:

Same as before. We just add the burst_duration.



Further comments:
The old formula adds the ready_aim time. This is false. Ready_aim time defines the time to focus on a new enemy and is applied only ONCE at the beginning of the fight. It also subtracts the fire aim time. This is false too.


Aftermath
(I'll quickly add another paragraph to give some perspective)
So, what about all this. Overall this doesn't sound like a huge change, does it?
Depends on the weapon you look at. Literally all DPS profiles in coh2.serealia.ca are incorrect. Some values are still close to each other, others are not. For example, the Ranger M1A1 carbine is shows as having 10 DPS in serealia at range 0-4. My in-game tests however showed something closer to 8 (39-40 seconds needed to kill 4 Partisans with in total 320 HP at point blank which leads a DPS of 8-8,2. This leads to a difference of 20% in this rather extreme case. My formula calculates 8,207 which seems to be way closer to the in-game situation. In serealia, the Tommy Bren gun starts at 4,1 and ends at 6,9 DPS, my formula calculates 4,5 (+10%) and 6,95 (+0,1%) respectively. Or the Gren K98 goes from 5,99 to 2,26 DPS, while the new formula returns 5,27 (-12%) to 2,16 (-4%). We're currently in a state of the game where things are in general decently balanced, every move we make now can naturally only be a tiny step. If we want to make further changes, we need to get the correct numbers. I checked some few weapons in the game and my model is consistent with what I measures in game regarding timings and a couple of DPS data I tried to measure. I encourage everyone to do some measurements though themselves and also report back what they got.



I’ll leave it at this for now, it is quite a wall of text already. I spent a lot of time on this already, if anyone has doubts about my formula I would kindly ask to gather some data yourself. I will be all ears for discussion, but after countless cycles of changing stats and stopping times, I would like to have a break on this.
I hope this helps for the upcoming commander patch. I might (no promises) release a python script soon to calculate and compare weapons.



Hannibal out



I have a python script that uses the old formula. If you tell what the adjustment that need to be made I can modify a line or two of that code in the mean time to check.
5 Apr 2021, 19:22 PM
#5
avatar of Hannibal
Senior Moderator Badge

Posts: 3114 | Subs: 2


I have a python script that uses the old formula. If you tell what the adjustment that need to be made I can modify a line or two of that code in the mean time to check.

https://www.coh2.org/file/19587/coh2-inf-dps-v0-5.zip

Well then I'll just hand out the pre-version right away.
This is a zip file containing the weapon_report as exported from the attribute editor (thanks to MMX for providing this since my table program fucks it up) and an ipynb file with the necessary code (I used jupyter notebook for that). Needs pandas, numpy and plotly.express libraries installed (most recent version, older ones should work too). You can also use seaborn instead, just change the last cell accordingly.
5 Apr 2021, 19:27 PM
#6
avatar of ZeroZeroNi

Posts: 1563


https://www.coh2.org/file/19587/coh2-inf-dps-v0-5.zip

Well then I'll just hand out the pre-version right away.
This is a zip file containing the weapon_report as exported from the attribute editor (thanks to MMX for providing this since my table program fucks it up) and an ipynb file with the necessary code (I used jupyter notebook for that). Needs pandas, numpy and plotly.express libraries installed (most recent version, older ones should work too). You can also use seaborn instead, just change the last cell accordingly.

Thanks
5 Apr 2021, 19:43 PM
#7
avatar of ZeroZeroNi

Posts: 1563


https://www.coh2.org/file/19587/coh2-inf-dps-v0-5.zip

Well then I'll just hand out the pre-version right away.
This is a zip file containing the weapon_report as exported from the attribute editor (thanks to MMX for providing this since my table program fucks it up) and an ipynb file with the necessary code (I used jupyter notebook for that). Needs pandas, numpy and plotly.express libraries installed (most recent version, older ones should work too). You can also use seaborn instead, just change the last cell accordingly.

Don't take this the wrong way but as a software dev some of the code just looks so inelegant.
5 Apr 2021, 19:52 PM
#8
avatar of Hannibal
Senior Moderator Badge

Posts: 3114 | Subs: 2


Don't take this the wrong way but as a software dev some of the code just looks so inelegant.

:D
No worries. I assume it is for a professional, but I then again for someone that taught himself programming in the evening with no real need for readable coding in the job that is excusable.
5 Apr 2021, 19:56 PM
#9
avatar of elchino7
Senior Moderator Badge

Posts: 8154 | Subs: 2

Hat off for the amount of work put in order for us to have the correct data.

Kudos.
5 Apr 2021, 19:56 PM
#10
avatar of ZeroZeroNi

Posts: 1563


:D
No worries. I assume it is for a professional, but I then again for someone that taught himself programming in the evening with no real need for readable coding in the job that is excusable.

Readability is fine,
But here is an optimization,

def correct_time(val):
if val>0: return math.ceil(val*8)*0.125
else: return 0
5 Apr 2021, 20:48 PM
#11
avatar of Hannibal
Senior Moderator Badge

Posts: 3114 | Subs: 2


Readability is fine,
But here is an optimization,

def correct_time(val):
if val>0: return math.ceil(val*8)*0.125
else: return 0

well yes I could have used the ceil function. However you shortened your version a bit too much because multiples of 0.125 get 0.125 added as well (for example, inputs of 0.125 and 0.2 must both generate 0.25 as output). I am happy if you have tips, however I'd rather move those to PM since code discussions are probably not very interesting for the other users.

Unless you spot a real error of course, then just post the fix or a fixed file here.
5 Apr 2021, 21:09 PM
#12
avatar of ZeroZeroNi

Posts: 1563


well yes I could have used the ceil function. However you shortened your version a bit too much because multiples of 0.125 get 0.125 added as well (for example, inputs of 0.125 and 0.2 must both generate 0.25 as output). I am happy if you have tips, however I'd rather move those to PM since code discussions are probably not very interesting for the other users.

Unless you spot a real error of course, then just post the fix or a fixed file here.

I have 1 more question:
What to do when burst length x rof is not a whole number.

A weapon can't fire say 17.5 rounds in a burst right???
5 Apr 2021, 21:14 PM
#13
avatar of Hannibal
Senior Moderator Badge

Posts: 3114 | Subs: 2


I have 1 more question:
What to do when burst length x rof is not a whole number.

A weapon can't fire say 17.5 rounds in a burst right???

As I wrote in the text, I am not sure what exactly happens in the game. But I have seen the weapon apply two different amounts of damage in successive bursts when I forced this situation. I am not sure if this fraction carries over to the next cycle or if there is a random pick. My best approximation is to just go with the fractional bullet and therefore fractional damage.
MMX
6 Apr 2021, 01:42 AM
#14
avatar of MMX

Posts: 999 | Subs: 1

awesome work man! from the limited testing i've done in the past to match my own dps calculations with the in-game behavior i know this is a very tough nut to crack. kudos for taking the time and figuring out the details, this will surely be of immense help to achieve proper unit balance (and hopefully also balance discussions).

i've got a question with respect to the formula; how does your code handle situations where delays (i.e. aim time × distance multi) would get below the 1 frame limit (which seems to occur frequently in serealia's data)? from what i've tested so far these delays have a minimum of 0.125 s and increase by multiples thereof, which i guess is what the apply add_125 function does?
6 Apr 2021, 06:33 AM
#15
avatar of Klement Pikhtura

Posts: 772

Sorry for stupid question, but does all this mean that in order to calculate the correct dps you need to add 0.125 sec to every delay stat during shooting, except reload time, if it is bigger then 0?
e.g. fire_aim_time + wind_up + wind_down + cooldown +0.125*4
6 Apr 2021, 06:35 AM
#16
avatar of Vipper

Posts: 13496 | Subs: 1

Sorry for stupid question, but does all this mean that in order to calculate the correct dps you need to add 0.125 sec to every delay stat during shooting, except reload time, if it is bigger then 0?
e.g. fire_aim_time + wind_up + wind_down + cooldown +0.125*4

The game uses ticks of 0.125 time. For the game the only times that exist are 0.125, 0.25, 0.375, 0.5
6 Apr 2021, 07:31 AM
#17
avatar of Hannibal
Senior Moderator Badge

Posts: 3114 | Subs: 2

jump backJump back to quoted post6 Apr 2021, 01:42 AMMMX
awesome work man! from the limited testing i've done in the past to match my own dps calculations with the in-game behavior i know this is a very tough nut to crack. kudos for taking the time and figuring out the details, this will surely be of immense help to achieve proper unit balance (and hopefully also balance discussions).

i've got a question with respect to the formula; how does your code handle situations where delays (i.e. aim time × distance multi) would get below the 1 frame limit (which seems to occur frequently in serealia's data)? from what i've tested so far these delays have a minimum of 0.125 s and increase by multiples thereof, which i guess is what the apply add_125 function does?


Sorry for stupid question, but does all this mean that in order to calculate the correct dps you need to add 0.125 sec to every delay stat during shooting, except reload time, if it is bigger then 0?
e.g. fire_aim_time + wind_up + wind_down + cooldown +0.125*4


jump backJump back to quoted post6 Apr 2021, 06:35 AMVipper

The game uses ticks of 0.125 time. For the game the only times that exist are 0.125, 0.25, 0.375, 0.5


I'll sum these up slightly since they target similar issues:
MMX:
I have not tested what happens below 0.125 seconds, simply because I did not think about it. For my testing I made Gren K98, Conscript mosin and Penal SVT (and both Axis HMGs respectively for burst weapons) carbon copies and then slightly altered stats to see what is happening. Once I had the model I compared the formula with some weapons as in the game and it seemed to fit (considering I cannot fully control distance within the tests). But you are right, maybe one more test is needed in that regard.

Kliement & Vipper:
The tank gun tests I did back then showed exactly this behaviour: Always round up to the next 0.125 step, but add at least 0.125. But either small arms behave differently, or the 64 bit update changed something. The stats for small arms all work differently. Some show the rounding behaviour, some show a simple 'just add 0.125', others stay as they are. Even if they are not a multiple of 0.125. A 1.3 second delay is possible for cooldown, on the other hand a 1.3 windup will always become 1.375. I have no idea why. I noted down how every single stat behaves in the stat overview spoiler. At least this is what my tests got me.
6 Apr 2021, 08:36 AM
#18
avatar of Klement Pikhtura

Posts: 772


I'll sum these up slightly since they target similar issues:
Kliement & Vipper:
The tank gun tests I did back then showed exactly this behaviour: Always round up to the next 0.125 step, but add at least 0.125. But either small arms behave differently, or the 64 bit update changed something. The stats for small arms all work differently. Some show the rounding behaviour, some show a simple 'just add 0.125', others stay as they are. Even if they are not a multiple of 0.125. A 1.3 second delay is possible for cooldown, on the other hand a 1.3 windup will always become 1.375. I have no idea why. I noted down how every single stat behaves in the stat overview spoiler. At least this is what my tests got me.

Ok, so if I understood you right fire_aim_time, wind_up, wind_down should be divisible by 0.125, or it's ried to in-game time, e.g. if fire_aim_tim finished in .387 fraction of a second it will be prolonged to 0.5 in real time? Also cooldown and burst duration can be anything and are not affected by the tickrate?

6 Apr 2021, 09:17 AM
#19
avatar of Hannibal
Senior Moderator Badge

Posts: 3114 | Subs: 2


Ok, so if I understood you right fire_aim_time, wind_up, wind_down should be divisible by 0.125, or it's ried to in-game time, e.g. if fire_aim_tim finished in .387 fraction of a second it will be prolonged to 0.5 in real time? Also cooldown and burst duration can be anything and are not affected by the tickrate?

wind_up and wind_down get rounded up to the next 0.125 step OR 0.125 added if they are already a multiple. Fire_aim time seems to be different for single and burst fire weapons. For single fire, you add 0.125 seconds and take that regardless if it is a multiple of 0.125 or not. Burst weapons do not add anything and just take the random value.

As an example:
wind_up is 0 seconds -> 0
wind_up is 1 second -> 1.125
wind_up is 1.1 seconds -> 1.125

single fire weapon:
fire_aim is 0 seconds -> not tested, according to the attribute editor it can't be smaller than 0.125 iirc
fire_aim is 1 second -> 1.125
fire_aim is 1.1 seconds -> 1.225

burst fire weapon:
fire_aim is 0 seconds -> not tested, according to the attribute editor it can't be smaller than 0.125 iirc
fire_aim is 1 second -> 1
fire_aim is 1.1 seconds -> 1.1



There is a second way to describe this that on one hand streamlines the logic, on the other hand introduces new logic errors. But it yields the same result.
If you export the weapon_report table from the attribute editor, single fire weapons have a burst duration of 0.125. In the case of single fire weapons, you could use the same formula as burst fire (that is, do not ad 0.125 seconds to fire_aim but add the 0.125 of the burst duration. This gives you the same result). On the other hand the attribute editor says that single fire weapons do not burst and therefore do not use any burst stats (CanBurst is set to 0).
So congrats to whoever at Relic wrote this, it is outdated and potentially has always been wrong. Or it has been right and the game treats fire_aim times of different weapon types differently.

What exactly happens in the end does not really matter. What matters is that the formula models what we see.
MMX
6 Apr 2021, 09:26 AM
#20
avatar of MMX

Posts: 999 | Subs: 1

just to chime in quickly because you mentioned burst duratiin. from what i know this is always at least 1 frame, even if can_burst is 0), as is aim time. hence even if you set all delays to 0 (for a ballistic weapon at least) the maximum number of shots per second is 4, or one every 2 frames
2 users are browsing this thread: 2 guests

Livestreams

Germany 1

Ladders Top 10

  • #
    Steam Alias
    W
    L
    %
    Streak
Data provided by Relic Relic Entertainment

Replay highlight

VS
  • U.S. Forces flag cblanco ★
  • The British Forces flag 보드카 중대
  • Oberkommando West flag VonManteuffel
  • Ostheer flag Heartless Jäger
uploaded by XXxxHeartlessxxXX

Board Info

499 users are online: 499 guests
4 posts in the last 24h
16 posts in the last week
28 posts in the last month
Registered members: 49902
Welcome our newest member, Calliste
Most online: 2043 users on 29 Oct 2023, 01:04 AM