Some thoughts on sword balance

I’ve put together a spreadsheet here https://docs.google.com/spreadsheets/d/14eQIe4AO_f6OxCt1XcB4NLAs6-5R1wQW-ydZG0orYdY/edit#gid=1787713396 for a data-driven discussion.

If you go to the “New Formula” tab, columns C-J have the basic numbers about the weapon, K-N calculate the hit_roll and crit values, and O-P calculate the average damage per attack per armor, crits, and rapid strikes.

If you look at src/melee.cpp and related bits of code (and no, there’s no synopsis, I’m afraid), you’ll see that a hit occurs when a randomly generated number on a normal distribution with a standard deviation of 25 and a mean value of 5 * (hit_roll - target's dodge) is greater than 0. Column S calculated the number of hits per 1000 attempts against the monster with the Dodge value in S4. Column T is the % of hits that are criticals, and columns U and V are damage per hit for non-critical and critical hits. Column W is the number of hits that are rapid strikes (assuming that rapid strikes occur 3/4ths of the time with a weapon with no other techniques, and (3+number of techs)/(4+number of techs) for weapons with more than 1 technique. Columns X and Y are rapid strike and rapid strike critical damage. Finally, Column Z

=100*((S8-W8)*((1-T8)*U8+T8*V8)+W8*((1-T8)*U8+T8*V8))/((1000-$W8)*$E8+$W8*$E8)

calculates average damage per 100 moves by multiplying the number of non-rapid strikes by the critical adjusted non-rapid strike damage and adding product of the number of rapid strikes and the critical adjusted rapid strike damage and dividing by the total number of moves used to perform all strikes, and then multiplying the results by 100 to get the average injury per 100 strikes.

Columns AB-AI and AK-AR repeat the process for survivor and smoker zombies, respectively. Column A averages the damage of the three targets, and multiplies by a fudge factor for the weapon’s reach: 1.5 for reach 2 or 1.75 for reach 3.

Any suggestions for improvement would be appreciated, as well as ways to refine it.

Thanks! I’ll take a look over this stuff this evening. :smiley:

1 Like

Please take my lack of feedback as, “you’ve put more thought into this than I have now”, rather than a lack of approval :smiley:

To the extent that I’ve reviewed the spreadsheet it looks rational and more nuanced than the existing function, my main thing is I want to wedge some sanity checks into the unit tests to avoid future regressions, which I’ll happily base on what you come up with.

Thanks! Yes, definitely want to add some unit tests for this stuff.

Ok, the cpp’s look pretty easy to read through and the combat math isn’t generally too crazy, so creating a discrete analysis function in a spreadsheet that would boil a weapon’s stats down to an expected damage/move against a given target dodge/armor profile doesn’t look too hard?

Made some progress last night - To hit wasn’t a problem, but we’ll see where damage goes. Can maybe get something together this evening - as long as I focus on just melee and ignore most of the special cases. Would like to find a solution that doesn’t require building and maintaining tables.

I prefer to use spreadsheets to do analysis of this kind of thing, because it’s easy to sort and filter stuff.

For instance, I’ve got a page for potential new values, and another page for new values filtered and sorted by weapon type. So I can look at this:

Shortsword
cutlass 23.53
sword bayonet 21.78
wakizashi 21.27
machete 17.73
survivor machete 17.53
makeshift machete 10.04
crude sword 8.83
sickle 5.10

And think that the crude sword should probably be a little better than the makeshift machete, if not quite as good as an actual machete.

Eventually, this is all going to have to be turned back into code in the melee_value() function.

Oh, I do almost all my work in spreadsheets, for exactly that reason. I’m not really much of a coder - enough to read and putter around - but I do a lot of excel and google sheets. :wink:

When I say I don’t want to maintain tables, I mean I don’t want whatever analysis function we end up with to rely on big lookup tables unless it really needs it.

For my part I’ll have oodles of tables just to amuse myself.

Wow. Google sheets doesn’t support sorting or filtering named ranges. That’s disappointing.

Ah well. Anyway, I looked over your sheets and given what they’re trying to accomplish they seem quite sufficient if you want to plug fixed comparitive values into weapons and have NPC’s wield the ‘best’ one - probably with a bit of extra weighting for the NPC’s skills tacked on to prefer weapons they are already competent with.

The other approach you could take altogether would be to write an ‘evaluation’ path alongside the core attack logic that lets the NPC execute an imaginary attack with a weapon they are considering against an enemy, with a flag to prevent anything from actually happening.

Aside from preventing effects you’d want to convert a few of the results along the way into %'s and Averages rather than hard outcomes and then spit out the final value of that - much like you’re doing in the spreadsheet, but with live values.

This has the advantage of being built into the game at a fundamental level so that NPC’s can always evaluate weapons on their own as they are added to the game, AND they can specifically choose weapons that are appropriate to both their own stats and condition, as well as those of the enemy they are fighting - but it adds a base layer of complexity to the main combat resolution path because you need to maintain the evaluation functions alongside the main outcome functions.

The actual process cost of doing this sort of evaluation shouldn’t really be that high, as long as the NPC’s don’t spam it unnecessarily, and stick to only evaluating actual melee weapons - unless they have none, in which case they may have to fall back to evaluating their pasta extruders and such…

All that being said, the current charts you’re working with seem to present a reasonably straightforward evaluation, and they are useful for doing game balance work as well, so I’d go with that as the first solution and think about a live combat path evaluation function for the future.

We already have 90% of the live evaluation code and I plan to add the rest at some point. Weapons are going to be approximately balanced based on the spreadsheet, so we can look at the numbers have not have vast discrepancies between similar weapons, but in play, an NPC is going to evaluate a weapon based on their own stats and skills - so a ST 5 NPC might not that think a lucern hammer is all that good and prefer a combat knife.

My real concern remains: is average damage per 100 moves against a zombie soldier, a zombie survivor, and a zombie smoker a good measure of a weapon’s general utility?
My second concern remains: should a weapon’s BLOCK ability count for it’s rating, or is effective damage the only concern?

This is just my 2 cents, for whatever it may be worth, but I’d think damage only is the way to go. Granted some weapons were built with defense in mind, but for the most part they’re designed for ease of use and the destruction they can dole out. Anything defense related is secondary. Otherwise you’ll have to start figuring for spiked shields or those pointy German helmets etc.

As we sort of discussed before I think block shouldn’t be factored in at this time. I don’t feel it appreciably benefits the user in combat over other weapons that lack it.

If for example we did a “live test” and the damage on the weapons were the same, I doubt the block of the weapon would be the difference between living and dying against a zombie soldier, since the far more important factor is if you can actually damage it in turn, otherwise it just takes slightly longer to kill you.

Currently NPCs favor attacks over tactical retreats as well, so with that in mind the damage, ability to hit, and armor penetration are the main things that are going to make a difference in their armaments.

The moment you start trying to take defense into account, you kind of go into a much more extensive form of evaluation where you have an NPC trying to judge Time To Kill vs. Time To Survive, and that’s much more complex - especially when in order for that evaluation to be useful, it would have to take into account not just your own stats, or one opponent, but the general field.

You could give a weapon some generic flat bonus for having medium or high block, but I’d weight it lightly, given that block is a modest benefit currently - just so that given two nearly equivalent weapons the NPC will prefer one with block over one without.

1 Like

Another week or two of hammering at the spreadsheet and I’ve got this proposal for rebalancing one-handed swords:

Item Name Item ID OVal Acc Moves Bash Cut Stab NVal Acc Moves Bash Cut Stab NVal
arming sword (fake) arming_sword_fake 18.09 2 108 14 2 0 11.39 2 108 13 2 0 10.65
arming sword (inferior) arming_sword_inferior 25.13 1 142 12 25 0 16.34 1 142 25 8 0 15.39
arming sword arming_sword 34.33 1 119 14 31 0 25.48 2 119 10 30 0 24.20
blade blade 5.00 -2 86 6 8 0 5.58 -1 86 6 8 0 7.03
broadsword broadsword 40.67 2 111 8 35 0 29.12 2 111 8 29 0 23.69
broadsword (inferior) broadsword_inferior 35.61 2 111 7 29 0 23.14 1 111 23 7 0 17.81
broadsword (fake) broadsword_fake 17.42 2 105 10 2 0 8.67 2 105 12 2 0 9.64
cavalry saber (fake) cavalry_sabre_fake 17.42 2 95 4 2 0 5.45 1 95 9 2 0 7.93
cavalry saber (inferior) cavalry_sabre_inferior 5.00 2 95 4 2 0 5.45 0 95 18 7 0 14.78
cavalry saber cavalry_sabre 41.62 2 100 2 26 0 19.64 1 100 6 28 0 22.03
crude sword sword_crude 11.78 -1 115 6 14 0 7.70 1 115 6 18 0 12.53
cutlass cutlass 36.94 2 100 7 27 0 23.68 1 100 8 27 0 22.20
cutlass (fake) cutlass_fake 16.49 2 103 8 2 0 7.38 1 103 12 1 0 9.43
cutlass (inferior) cutlass_inferior 34.69 2 100 6 25 0 21.06 0 100 23 7 0 17.39
dao dao 27.56 2 107 6 18 0 14.78 0 107 7 28 0 18.56
fencing epee fencing_epee 21.03 2 95 3 0 7 7.18 0 95 3 0 7 5.45
fencing foil fencing_foil 14.72 2 92 1 0 2 3.73 0 92 1 0 2 2.71
fencing saber fencing_sabre 18.95 2 91 1 0 6 5.64 0 91 1 0 6 4.21
firebrand (off) broadfire_off 33.60 1 125 8 35 0 23.77 1 125 8 29 0 19.26
firebrand (on) broadfire_on 33.60 1 125 8 35 0 23.77 3 125 8 29 0 22.60
jian jian 36.90 2 110 8 30 0 24.82 2 110 5 31 0 24.07
jian (fake) jian_fake 16.49 2 103 8 2 0 7.38 2 103 11 2 0 9.00
jian (inferior) jian_inferior 31.84 2 110 7 24 0 19.02 1 110 21 8 0 17.16
khopesh khopesh 26.22 1 105 7 19 0 14.90 0 105 16 27 0 23.58
kukri kukri 37.53 1 84 2 20 0 16.15 0 84 7 26 0 21.60
machete machete 33.91 2 89 6 20 0 19.45 1 89 6 21 0 18.50
makeshift machete makeshift_machete 20.21 1 106 4 14 0 10.04 0 106 5 16 0 10.19
makeshift macuahuitl glass_macuahuitl 20.24 1 116 7 14 0 10.61 0 116 7 14 0 9.17
monomolecular blade bio_blade_weapon 53.44 3 78 0 36 0 39.51 1 78 0 33 0 30.45
nailboard nailboard 14.25 1 108 10 0 3 7.32 1 108 10 0 3 0.00
No. 9 (On) firemachete_on 23.66 1 119 6 20 0 13.26 2 119 6 21 0 15.18
No. 9 (Off) firemachete_off 23.66 1 119 6 20 0 13.26 0 119 6 21 0 12.06
pair of butterfly swords butterfly_swords 31.00 2 118 6 26 0 18.70 1 118 7 32 0 22.32
rapier (fake) rapier_fake 16.76 2 100 4 2 0 5.18 2 100 9 0 2 8.24
rapier (inferior) rapier_inferior 5.00 2 100 4 2 0 5.18 0 100 18 0 8 14.74
rapier rapier 38.04 2 105 2 0 29 15.50 1 105 2 0 33 24.33
scimitar (fake) scimitar_fake 11.89 1 106 6 2 0 5.45 1 106 12 2 0 9.21
scimitar scimitar 31.66 1 115 6 30 0 20.79 1 115 6 34 0 24.06
scimitar (inferior) scimitar_inferior 26.79 1 115 5 24 0 15.63 0 115 23 8 0 15.58
scythe blade blade_scythe 5.00 -2 105 6 8 0 4.57 -1 105 6 8 0 5.76
shishkebab (off) shishkebab_off 13.74 0 133 4 14 0 6.90 0 133 4 14 0 6.90
shishkebab (on) shishkebab_on 13.74 0 133 4 14 0 6.90 2 133 4 14 0 6.90
survivor machete survivor_machete 41.73 2 90 6 20 0 19.24 1 90 6 21 0 18.30
sword bayonet sword_bayonet 39.07 1 108 8 25 0 18.82 1 108 7 29 0 21.78
sword cane sword_cane 5.00 0 94 2 0 25 10.13 0 94 2 0 25 17.02
wakizashi (fake) wakizashi_fake 19.33 2 98 7 2 0 7.14 1 98 8 2 0 7.02
wakizashi wakizashi 36.38 1 102 3 24 0 16.54 1 102 2 30 0 21.27
wakizashi (inferior) wakizashi_inferior 35.20 2 102 3 20 0 15.19 0 102 17 7 0 13.10
xiphos sword_xiphos 29.35 2 110 8 20 0 16.84 110 8 28 0 21.04

OVal is the current NPC evaluation function, and the first set of columns are the weapon’s current stats, ending with NVal, which is the current weapon’s stats using my new NPC evaluation formula.
The second set of stats is what I’m proposing to use, along with the NVals for the new stats.

A couple of notes here: I’ve gone through and broken down the grip, length, striking surface, and balance for every weapon in the game and recalculated accuracy from that. Most “real” swords have linear striking surfaces and good balance, but their flaming variants have “every” striking surface when on and neutral balance at all times to account for the balance of the gasoline system. Fake and inferior weapons have neutral balance, and fake weapons upgrade to “any” strike surface because they’re actually fancy clubs. Asian weapons do roughly equivalent damage as European weapons, but Asian weapons are more cutting and European weapons are more bashing - this is not strictly accurate, but it does differentiate them a little.

The target value for 1 handed swords was 24, and 22 for shortswords. Makeshift or improvised weapons were generally set to be roughly equivalent to inferior variants of real weapons. Inferior weapons get 1/2 of the real weapon’s Cut or Stab damage added to their bash damage and the cut or stab damage reduced to 25% of normal; fake weapons have half the bash damage of inferior weapons and their cut or stab damage is reduced to 25% of the inferior weapon. A little arbitrary, but it’s consistent.

The “Comparison” tab of the spreadsheet has all of this color coded to show numbers that were increased or decreased, and the “Raw” tab has the values I used to calculate accuracy if anyone wants to double-check my work.

Feedback welcome.

3 Likes

So much of the discussion that is going on here is both far better researched and in depth than I could meaningfully contribute to, though there is one facet I’m curious about being brought up. Having watched a few ‘pop-culture medieval’ videos, one aspect of curved blades in particular I’ve seen is the concept of ‘edge-alignment’ being much easier to achieve with a curved weapon. As in, the curve of the blade and the motion of slashing makes an accurate cute more attainable by someone with less practice.

This seems to me like it would be attractive to a survivor with low skills, rather than using a straight edged weapon that could (according to some) more easily roll during the swing and hit with a less aligned edge. Once sufficient skill with a weapon is attained, that advantage obviously matters very little, but it was something that I didn’t notice being brought up in the discussion thus far.

RE: Block rating and the value calculation, perhaps damage per 100 turn should be calculated in both directions. I’d even go so far as to make damage taken weight more than damage dealt, unless the character can reasonably expect to one-shot regular zombies.

I guess what I’m saying is that in all these NPC decision making calculations, you probably wouldn’t go wrong to lean towards a preference for survivability over literally any other factor. Block certainly improves your survivability, especially if you don’t really want to fight (I’d assume most people wouldn’t).

edit RE: test fights, I’d add a small mob of zombies, 3 to 5. How often do you fight a single zombie?

That’s going to be below the level of resolution in the game. The accuracy categories are very broad and don’t account for marginal differences like that.

An NPC’s damage taken is going to depend on armor and Dodge. There’s a place for evaluating Turns to Kill and Delta Turns Till Death (see https://github.com/CleverRaven/Cataclysm-DDA/issues/25687) but it’s going to really complicate weapon evaluation. Maybe it’s reasonable that you prefer knives if you’re unarmored and sledgehammers if you’re in plate, but it works out to 45 scenarios:

  • high armor zombie, mixed dodge/armor zombie, high dodge zombie
  • high accuracy and high damage zombie, low accuracy and high damage zombie, middle accuracy and middle damage zombie, high accuracy and low damage zombie, low accuracy and low damage zombie
  • high armor NPC, mixed armor and dodge NPC, unarmored but dodgy NPC

Very fair, just thought it was worth asking about.

On the whole offensive vs survivable side of things, I don’t think that offensive ability contributing to defensive play can be understated. A zombie that’s ‘dead’ again can’t keep attacking, and given how NPCs don’t take terrain advantages into account, killing something, especially one of a group of zeds, keeps the incoming damage down.

Perhaps for that reason biasing the value towards particularly tough to kill enemies would be more useful? A high dodge/low armor enemy will eventually be put down with enough attacks against it no matter what, but if you can’t get past the armor of a tanky one you’re gonna die unless you run, especially if you’re wasting attacks on armor when getting swarmed. Like being the giant spider who goes up against a properly armored survivor.

Significantly curved blades can actually be quite awkward for a novice user. While Its true that it remains clear where the edge of the blade is, the problem is that the blade is much more likely to roll due to impacts, especially if it’s not well balanced for combat (such as a makeshift blade might be).

Basically there’s just a lot more physics that can happen with a curved blade in the chaos of melee, and a novice will have a harder time keeping the blade straight, or even keeping their grip on it due to these forces.

The grip on a regular sword is generally not round, it’s oval, and in such a manner that the ‘natural’ grip and swing will tend to bring the edge of the blade to bear. No guarantee, but as a rule I’d start a novice with a relatively short, straight blade, or perhaps gently curved one, such as a katana - but not a dramatically swept blade such as a Scimitar.

Also, it’s important to note that straight blades are usually double edged, which allows a wider range of swing motions, and you can’t get your grip ‘backwards’ - curved blades are always single edged, which is another limitation and potential thing for a novice to get screwed up with in a fight.

Ultimately if you’re looking for NPC behavior that effectively compliments the player character, that’s only really going to work if the player can directly equip and define an NPC follower’s behaviors at a relatively detailed level. The ability to yell commands in battle or to force-equip them with specific armor and weapons in order to complement whatever their role in combat is intended to be.

If the goal is really just about NPC personal effectiveness and survival, their movement behaviors are going to be FAR more important than whether they choose to use a katana or a longsword (as long as they don’t charge into battle with a pasta extruder…). Simply choosing correctly when you’re in a position to stick and fight or when to re-position or run is the deciding survival factor about 95% of the time.