Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

melee: make polearms do less damage against adjacent targets #39694

Merged
merged 9 commits into from
Apr 19, 2020
6 changes: 6 additions & 0 deletions data/json/flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,12 @@
"//": "Increases warmth for hands if the player's hands are cold and the player is wielding nothing.",
"info": "This clothing has <info>pockets</info> to warm your hands when you are wielding nothing."
},
{
"id": "POLEARM",
"type": "json_flag",
"context": [ "GENERIC", "TOOL" ],
"info": "As a weapon, this item needs considerable space to use properly and does 70% of its normal damage to adjacent enemies."
},
{
"id": "POWERED",
"type": "json_flag",
Expand Down
4 changes: 2 additions & 2 deletions data/json/items/melee/bludgeons.json
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@
"description": "This is a versatile polearm with a spiked hammer head, a spike, and a hook attached to a long stick.",
"price": 50000,
"material": [ "wood", "steel" ],
"flags": [ "DURABLE_MELEE", "REACH_ATTACK", "NONCONDUCTIVE", "SHEATH_SPEAR", "SPEAR", "ALWAYS_TWOHAND" ],
"flags": [ "DURABLE_MELEE", "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "SPEAR", "ALWAYS_TWOHAND" ],
"techniques": [ "WBLOCK_1", "WIDE", "SWEEP" ],
"weight": "3200 g",
"volume": "3750 ml",
Expand All @@ -583,7 +583,7 @@
"price": 4000,
"price_postapoc": 500,
"material": [ "wood", "aluminum" ],
"flags": [ "REACH_ATTACK", "NONCONDUCTIVE", "SHEATH_SPEAR", "SPEAR", "ALWAYS_TWOHAND" ],
"flags": [ "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "SPEAR", "ALWAYS_TWOHAND" ],
"techniques": [ "WBLOCK_1", "SWEEP" ],
"weight": "2700 g",
"volume": "3750 ml",
Expand Down
26 changes: 13 additions & 13 deletions data/json/items/melee/spears_and_polearms.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"color": "light_gray",
"techniques": [ "WIDE", "BRUTAL" ],
"qualities": [ [ "CUT", 1 ], [ "BUTCHER", -22 ] ],
"flags": [ "FRAGILE_MELEE", "NONCONDUCTIVE", "SHEATH_SPEAR", "REACH_ATTACK", "ALWAYS_TWOHAND" ]
"flags": [ "FRAGILE_MELEE", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "REACH_ATTACK", "ALWAYS_TWOHAND" ]
},
{
"id": "spear_spike",
Expand Down Expand Up @@ -278,7 +278,7 @@
"description": "This is a versatile polearm with an axe blade, a spike, and other fun things attached to a long stick.",
"price": 50000,
"material": [ "wood", "steel" ],
"flags": [ "DURABLE_MELEE", "REACH_ATTACK", "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"flags": [ "DURABLE_MELEE", "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"techniques": [ "WBLOCK_1", "WIDE", "SWEEP" ],
"weight": "3175 g",
"volume": "3750 ml",
Expand All @@ -297,7 +297,7 @@
"description": "This is a dull, cheaply made replica of a polearm with an axe blade, a spike, and other fun things attached to a long stick.",
"price": 5000,
"material": [ "wood", "aluminum" ],
"flags": [ "REACH_ATTACK", "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"flags": [ "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"techniques": [ "WBLOCK_1", "SWEEP" ],
"weight": "1644 g",
"volume": "3750 ml",
Expand All @@ -317,7 +317,7 @@
"price": 50000,
"material": [ "steel", "wood" ],
"qualities": [ [ "CUT", 1 ], [ "BUTCHER", -28 ] ],
"flags": [ "DURABLE_MELEE", "REACH_ATTACK", "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"flags": [ "DURABLE_MELEE", "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"techniques": [ "WIDE", "WBLOCK_1" ],
"weight": "2100 g",
"volume": "2500 ml",
Expand All @@ -341,7 +341,7 @@
"bashing": 6,
"cutting": 37,
"qualities": [ [ "CUT", 1 ], [ "BUTCHER", -24 ] ],
"flags": [ "DURABLE_MELEE", "REACH_ATTACK", "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"flags": [ "DURABLE_MELEE", "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"price": 80000,
"price_postapoc": 9500
},
Expand All @@ -360,7 +360,7 @@
"cutting": 21,
"to_hit": 2,
"qualities": [ [ "CUT", 1 ], [ "BUTCHER", -24 ] ],
"flags": [ "REACH_ATTACK", "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"flags": [ "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"price": 8000,
"price_postapoc": 1500
},
Expand All @@ -378,7 +378,7 @@
"bashing": 13,
"cutting": 1,
"to_hit": -1,
"flags": [ "REACH_ATTACK", "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"flags": [ "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ],
"price": 8000,
"price_postapoc": 500
},
Expand All @@ -396,7 +396,7 @@
"volume": "2250 ml",
"bashing": 2,
"cutting": 24,
"flags": [ "STAB", "REACH_ATTACK", "SHEATH_SPEAR" ],
"flags": [ "STAB", "POLEARM", "REACH_ATTACK", "SHEATH_SPEAR" ],
"//": "Description says it can slash. STAB currently doesn't slash, but at least it doesn't give the spear bonus",
"price": 8000,
"price_postapoc": 4500,
Expand Down Expand Up @@ -460,7 +460,7 @@
"color": "brown",
"techniques": [ "IMPALE", "WBLOCK_2" ],
"qualities": [ [ "COOK", 1 ] ],
"flags": [ "DURABLE_MELEE", "SPEAR", "REACH_ATTACK", "REACH3", "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ]
"flags": [ "DURABLE_MELEE", "POLEARM", "SPEAR", "REACH_ATTACK", "REACH3", "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ]
},
{
"id": "pike_fake",
Expand All @@ -481,7 +481,7 @@
"looks_like": "pike",
"techniques": [ "IMPALE", "WBLOCK_2" ],
"qualities": [ [ "COOK", 1 ] ],
"flags": [ "SPEAR", "REACH_ATTACK", "REACH3", "NONCONDUCTIVE", "ALWAYS_TWOHAND" ]
"flags": [ "POLEARM", "SPEAR", "REACH_ATTACK", "REACH3", "NONCONDUCTIVE", "ALWAYS_TWOHAND" ]
},
{
"id": "pike_inferior",
Expand All @@ -502,7 +502,7 @@
"looks_like": "pike",
"techniques": [ "IMPALE", "WBLOCK_2" ],
"qualities": [ [ "COOK", 1 ] ],
"flags": [ "SPEAR", "REACH_ATTACK", "REACH3", "NONCONDUCTIVE", "ALWAYS_TWOHAND" ]
"flags": [ "POLEARM", "SPEAR", "REACH_ATTACK", "REACH3", "NONCONDUCTIVE", "ALWAYS_TWOHAND" ]
},
{
"type": "GENERIC",
Expand All @@ -521,7 +521,7 @@
"color": "light_gray",
"techniques": [ "WIDE", "BRUTAL" ],
"qualities": [ [ "CUT", 1 ], [ "BUTCHER", -22 ] ],
"flags": [ "DURABLE_MELEE", "NONCONDUCTIVE", "SHEATH_SPEAR", "REACH_ATTACK", "ALWAYS_TWOHAND" ]
"flags": [ "DURABLE_MELEE", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "REACH_ATTACK", "ALWAYS_TWOHAND" ]
},
{
"id": "spear_dory",
Expand Down Expand Up @@ -559,7 +559,7 @@
"symbol": "/",
"color": "yellow",
"techniques": [ "WBLOCK_1", "DEF_DISARM" ],
"flags": [ "DURABLE_MELEE", "REACH_ATTACK", "ALWAYS_TWOHAND" ]
"flags": [ "DURABLE_MELEE", "POLEARM", "REACH_ATTACK", "ALWAYS_TWOHAND" ]
},
{
"id": "spear_stone",
Expand Down
51 changes: 51 additions & 0 deletions data/mods/TEST_DATA/items.json
Original file line number Diff line number Diff line change
Expand Up @@ -451,5 +451,56 @@
"storage": "15 L",
"material_thickness": 2,
"flags": [ "FANCY", "OVERSIZE", "BELTED", "RESTRICT_HANDS", "WATER_FRIENDLY" ]
},
{
"type": "GENERIC",
"id": "test_clumsy_sword",
"name": "TEST clumsy sword",
"description": "A poorly balanced sword for test purposes",
"category": "spare_parts",
"weight": "1250 g",
"to_hit": -1,
"color": "dark_gray",
"symbol": "/",
"material": [ "steel" ],
"volume": "1 L",
"bashing": 32,
"cutting": 32,
"price": 7500,
"price_postapoc": 300
},
{
"type": "GENERIC",
"id": "test_normal_sword",
"name": "TEST normal sword",
"description": "A sword for test purposes",
"category": "spare_parts",
"weight": "1250 g",
"to_hit": 1,
"color": "dark_gray",
"symbol": "/",
"material": [ "steel" ],
"volume": "1 L",
"bashing": 32,
"cutting": 32,
"price": 7500,
"price_postapoc": 300
},
{
"type": "GENERIC",
"id": "test_balanced_sword",
"name": "TEST balanced sword",
"description": "A well-balanced sword for test purposes",
"category": "spare_parts",
"weight": "1250 g",
"to_hit": 3,
"color": "dark_gray",
"symbol": "/",
"material": [ "steel" ],
"volume": "1 L",
"bashing": 32,
"cutting": 32,
"price": 7500,
"price_postapoc": 300
}
]
51 changes: 34 additions & 17 deletions doc/GAME_BALANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,35 +99,52 @@ A measure of how well-suited the item is for being swung/thrust/etc. This factor

## Damage
Weapon's relative strength is based on an approximate formula involving its damage, to-hit, techniques and few other factors.
This strength will be expressed in "points" or dpt (damage per turn) as damage per turn is the most significant balancing factor.

### Damage per turn
Melee weapon's relative strength is measured by damage per turn (more precisely: damage per 100 moves). The damage is sum of all damage types (average of min/max where random) from the weapon alone, without including strength in the calculation.
For bashing weapons, it is assumed the character can achieve the maximum damage, but this strength isn't added to damage (or critical damage).
### Damage per second
A melee's weapon damage per second (dps) is calculated past armor against a sample group of monsters with a range of dodge and armor values: a soldier zombie (low dodge, high bash and cut armor), a survivor zombie (medium dodge, some bash and cut armor), and a smoker zombie (high dodge, no armor). This should correctly weigh accuracy, criticals, and damage without over valuing any of them.

### To-hit
While not a direct measure of damage, to-hit bonus has to be included in the calculations, as it has a significant effect on actual damage output (through hit and crit rate).
In code, this is calculated using the item::effective_dps() function, which takes a character and a monster. It calculates the relative accuracy of the character and weapon against the monster's defenses and determines the hit rate from a table lookup. It also determines the number of critical hits. Number of hits is hit rate * 10,000, and number of misses is 10,000 - number of hits.

Each point of to-hit is "worth" roughly a 10% increase/decrease in damage per turn or 2.5 points of damage per turn (whichever is higher).
For both critical and non-critical hits, average damage is calculated based on the weapon's stats and the user's skill. Monster armor absorbs the damage, and then the damage is multiplied by the number of hits: either critical hits for the critical hit case, or total hits - critical hits for the non critical hit case. If the weapon has the rapid strike technique, the total damage is halved, and then the average damage is recalculated, multiplied by 0.66, and absorbed by monster armor again to account for rapid strikes.

### Techniques
Rapid strike technique increases damage per turn by 0.66 / 0.5 = 132%
Other techniques are generally too situational to be worth any points here.
Number of moves is calculated as attack speed * ( number of misses + number of non-critical hits + number of critical hits ) for weapons without rapid strike, or attack speed * ( number of misses + number of non-critical hits / 2 + number of critical hits / 2 ) + attack speed / 2 * ( number of non-critical hits / 2 + number of critical hits / 2 ) for weapons without rapid strikes.

Damage per second against a particular monster is total damage * 100 / number of moves (100 for the 100 moves/second). Overall dps is the average of the dps against the three reference monsters.

### Critical hits
A double critical can occcur when a second hit roll is made against 1.5 * the monster's dodge. Double critical hits have a higher chance of occurring than normal critical hits. For each hit, the chance of achieving either a double critical hit or a normal critical hit is calculated, and then if a random number is less than the critical chance, the critical occurs. Both double and normal critical hits have the same effect, but the chance of them occurring is different.

**Note** The critical hit system is stupid and complicated and produces weird results. Double critical hits should have a chance of occuring when the original hit roll is more than 1 standard deviation above the mean, which is simple and faster to calculate than the current system.

### Other factors
Reach is worth +20% at reach 2, +35% at reach 3.

A weapon that is usuable by a known martial art is worth +50%.

### Weapon tiers
Damage per turn should put the weapon into one of those categories:
Relative value should put the weapon into one of those categories:

<2 - Not weapons. Those items may be pressed into service, but are unlikely to be better than fists. Plastic bottles, rocks, boots.

2-5 - Tools not meant to strike and improvised weapons. Two-by-fours, pointy sticks, pipes, hammers.

<10 - Not weapons. Those items may be pressed into service, but are unlikely to be better than fists. Plastic bottles, rocks, boots.
6-11 - Dangerous tools or crude dedicated weapons. Golf clubs, two-by-swords, wooden spears, knife spears, hatchets, switchblades, tonfas, quarterstaves.

11-15 - Tools not meant to strike and improvised weapons. Two-by-fours, pointy sticks, pipes, hammers.
12-15 - Good dedicated weapons or the most dangerous of tools. Wood and fire axes, steel spears, electric carvers, kukris, bokken, machetes, barbed wire bats.

16-25 - Dangerous tools or crude dedicated weapons. Golf clubs, two-by-swords, wooden spears, knife spears, hatchets, switchblades, tonfas, quarterstaves.
20-35 - Weapons of war, well designed to kill humans. Wakizashis, katanas, broadswords, zweihanders, combat knifes, battle axes, war hammers, maces, morningstars.

26-35 - Good dedicated weapons or the most dangerous of tools. Wood and fire axes, steel spears, electric carvers, kukris, bokken, machetes, barbed wire bats.
35+ - Sci-fi stuff. Diamond katanas, monomolecular blades, lightsabers and chainswords.

36-45 - Weapons of war, well designed to kill humans. Wakizashis, katanas, broadswords, zweihanders, combat knifes, battle axes, war hammers, maces, morningstars.
Specific weapon balancing points:
20 - combat knifes
22 - short blades
24 - long blades, short axes, and short flails
26 - two handed blades, long axes, most spears
28 - two handed axes and polearms
30 - combat spears

46+ - Sci-fi stuff. Diamond katanas, monomolecular blades, lightsabers and chainswords.
Improvised weapons generally have about 75% of the value of a real weapon.

## Other melee balancing factors
### Attack speed
Expand Down
3 changes: 2 additions & 1 deletion doc/JSON_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -795,10 +795,11 @@ List of known flags, used in both `terrain.json` and `furniture.json`.
- ```NO_CVD``` Item can never be used with a CVD machine
- ```NO_RELOAD``` Item can never be reloaded (even if has a valid ammo type).
- ```NO_UNWIELD``` Cannot unwield this item.
- ```POLEARM``` Item is clumsy up close and does 70% of normal damage against adjacent targets. Should be paired with REACH_ATTACK. Simple reach piercing weapons like spears should not get this flag.
- ```REACH_ATTACK``` Allows to perform reach attack.
- ```SHEATH_KNIFE``` Item can be sheathed in a knife sheath, it applicable to small/medium knives (with volume not bigger than 2)
- ```SHEATH_SWORD``` Item can be sheathed in a sword scabbard
- ```SPEAR``` When making reach attacks intervening THIN_OBSTACLE terrain is not an obstacle
- ```SPEAR``` When making reach attacks intervening THIN_OBSTACLE terrain is not an obstacle. Should be paired with REACH_ATTACK.
- ```UNARMED_WEAPON``` Wielding this item still counts as unarmed combat.
- ```WHIP``` Has a chance of disarming the opponent.

Expand Down
Loading