Differentiating between melee and thrown weapons

As was brought up in the “guidelines for melee weapons stats” (or something) thread, there are a number of melee weapons that due to their stats are excessively good as thrown weapons as well. I’ll lay out how throwing performance is calculated, and we can discuss what we can do to bring throwing performance in line with what you would actually expect.
Here’s the code that determines accuracy: (I’ve added some extra explanations and removed extraneous code)

    int deviation = 0;
    // Thrown weapons get an automatic range penalty compared to ranged weapons.
    int trange = 1.5 * rl_dist(p.posx, p.posy, tarx, tary);

    // This chunk is all about skills and stats, so not really pertinent to the discussion.
    int skillLevel = p.skillLevel("throw");
    if (skillLevel < 3) deviation += rng(0, 8 - skillLevel);
    if (skillLevel < 8) deviation += rng(0, 8 - skillLevel);
    else deviation -= skillLevel - 6;
    deviation += p.throw_dex_mod();
    if (p.per_cur < 6) deviation += rng(0, 8 - p.per_cur);
    else if (p.per_cur > 8) deviation -= p.per_cur - 8;
    deviation += rng(0, p.encumb(bp_hands) * 2 + p.encumb(bp_eyes) + 1);

    // "Oversized" items get a penalty, starting at about baseball bat sized items.
    if (thrown.volume() > 5)
        deviation += rng(0, 1 + (thrown.volume() - 5) / 4);
    // Extremely small items also get a penalty.
    if (thrown.volume() == 0)
        deviation += rng(0, 3);

    // This is um... weird, and should probably be fixed.
    // You have an ideal weight based on your strength, and the further away from that weight
    // the item is, the bigger your penalty, so if you're super-strong,
    // it's very difficult to throw small items.
    // I suspect what it WANTED to do was impose a penalty for high weight items
    // without giving a bonus for light items. Filed an issue, moving on...
    deviation += rng(0, 1 + abs(p.str_cur - thrown.weight() / 113));

That’s actually it, all it cares about is volume and weight. The simplest thing we could do is add a “throwable” flag, and either a bonus for having it, a penalty for not having it, or both. I think that’s sufficient, but if it’s really needed we could have multiple levels of throwability, or possibly a seperate to-hit and/or damage stat for throwing vs melee. There’d have to be a really good reason though.

On to damage, it’s calculated like this:

    // Sum up item weight, item bash damage stat, and character strength.
    // Then divide by volume of the item.
    int real_dam = (thrown.weight() / 452 +
                    thrown.type->melee_dam / 2 +
                    p.str_cur / 2) /
                   double(2 + double(thrown.volume() / 4));
    // Cap damage based on item weight, no knocking zombies over with feathers.
    if (real_dam > thrown.weight() / 40)
        real_dam = thrown.weight() / 40;
    // Special boost for railgun.
    if (p.has_active_bionic("bio_railgun") && (thrown.made_of("iron") || thrown.made_of("steel")))
    {
        real_dam *= 2;
    }
...
    // This determines if you "stick" a item with sharp bits, it's totally based on skill.
    if (rng(0, 100) < 20 + skillLevel * 12 && thrown.type->melee_cut > 0) {
        // Only factor in cutting armor if we're doing cutting damage.
        // The code does account for bash armor,
        // but it's kind of scattered around and not interesting for our purposes.
        if (thrown.type->melee_cut > z.armor_cut())
            dam += (thrown.type->melee_cut - z.armor_cut());
    }
    

This overall seems sensible, but there are a few things that jump out at me that could be improved.

One is that items are more likely to miss at long range, but they do exactly the same amount of damage, no matter how for away the target is. With small dense items this is fine, but unaerodynamic items should have significant slowdown from air resistance. Something like losing damage with each space travelled based on volume/weight, possibly with a “thrown” flag factored in. Good throwing weapons like rocks wouldn’t lose anything, but high volume to low weight items like blankets or paper wrappers would lose huge amounts.

It assumes all items with cutting damage are like throwing knives, if something is thrown like a spear, it’s not an issue, so we need a flag to either trigger this or bypass it.

It seems like cutting damage should scale with how hard you throw it.

A minor point is that if you accidentally hit a monster with e.g. a throwing knife, it still applies your skill to determine if it “sticks”, it should be totally random in this case. (if you don’t know the range, you can’t throw it correctly)

As for differentiating between items intended for throwing and not, there is the same choices, either a “good for throwing” tag, or seperate throwing stats. Or something else better of course.

Finally we have range determination:

 // If it's too heavy relative to strength, we can't throw it at all.
 if ((tmp.weight() / 113) > int(str_cur * 15))
  return 0;
 // Increases as weight decreases until 150 g, then decreases again
 int ret = (str_cur * 8) / (tmp.weight() >= 150 ? tmp.weight() / 113 : 10 - int(tmp.weight() / 15));
 // Decrease with volume, anything under 4 gets no penalty.
 ret -= int(tmp.volume() / 4);
 // Special boost for railgun.
 if (has_active_bionic("bio_railgun") && (tmp.made_of("iron") || tmp.made_of("steel")))
    ret *= 2;
 if (ret < 1)
  return 1;
 // Cap at double our strength + skill
 if (ret > str_cur * 1.5 + skillLevel("throw"))
   return str_cur * 1.5 + skillLevel("throw");

Everything here seems fine, but of course there’s room to factor in throwability.

After looking through these, I tenatively think a “throwable” flag added to select weapons, with appropriate bonuses applied across the board would do what we need, but if anyone has ideas on something better, let’s hear them.
Also I’ve turned up a few bugs and opportunities for improvement, all of which would be internal to the throwing code except for adding a flag for “tumbling cutting weapon” vs “non-tumbling cutting weapon”, given stuff like thrown swords, I think the best option is a special flag for “non-tumbling thrown weapons”, to be applied to javelins, spears, darts, shuriken and any other weapons that don’t require extra effort to make them stick when thrown.
Also I think I’ll stick most of the comments I added for readability here into the actual code :wink:

Ah, I misunderstood Glyph’s discussion. I thought those guideline categories were newly proposed statistics for weapons (Even though you twice pointed out they weren’t, slaps-forehead).

I understand that adding these attributes would be a pretty big effort (updating the json for every object in the game, updating all the damage & miss calculations to account for them, etc), but I think it would pay huge dividends in the long run. The same statistics could be applied to determine the usefulness of all items as both melee and throwing weapons, without having to arbitrarily decide what items should have a “throwable” flag, and what not. I’m all for more immediate fixes to address the issue of melee items inappropriately used for throwing, but could this be earmarked as a long term goal?

For a possible long term refactor: Below are the 3 of the 4 categories mentioned in the other thread. (I’m leaving out length)

Grip - Grip is a measure of how well you can control the weapon to quickly respond to situational changes.
Striking Surface - Some weapons need to strike in a certain way to be effective. Others are more difficult to use “incorrectly”.
Balance - A measure of how well-suited the item is for being swung/thrust/etc. This factors in both how well suited it is to be handled and overall weight, so light but lopsided items would have ok balance, and very heavy but evenly balanced items would have worse effective balance.

Here’s how they could apply to throwing accuracy, damage, and range

Accuracy: Positively correlated with Grip, Balance, and Striking Surface. (The negative striking surface values indicate it’s harder to hit your target with the right part of your thrown item)

Damage: Positively correlated with Grip (you can throw harder with a good grip), Negatively correlated with Striking Surface (Negative Striking Surface Values means you want to hit with a specific part of the weapon. When you do, it does more damage)

Range: Positively correlated with Grip (a good grip makes it easier to throw farther)

The exact same numerical values used for calculating On-Hit bonuses/penalties could be used in calculating the accuracy, damage, and range of thrown weapons, using the correlations above. I’ll repost those values and descriptions from the last thread:

Values from the other thread:

Grip - Grip is a measure of how well you can control the weapon to quickly respond to situational changes.
-1 - Particularly hard to grip items, (especially those that are innately slipper or very rounded with no obvious gripping edge) such as basketballs and barrels, or which are dangerous to hold because of very sharp edges, like scrap metal and broken glass.
+0 - Any object that doesn’t fall into one of the categories below. Examples include 2x4s, computer monitors, wires, stingers and clothing. Basically, anything that has a grippable component, but which is too thick, too thin, or too flimsy to grab comfortably in a way that can reliably control the object.
+1 - A weapon with a fairly solid grip, like a pipe, a rock, guitar neck, pool cue or a heavy stick
+2 - A weapon with a dedicated grip shaped to the hand, like a sword, axe, knife, or police baton, or that is strapped to the body (or is a piece of the body). Fists would get a +2 bonus here, bringing them to “0” total, since none of the others would apply.

Striking Surface - Some weapons need to strike in a certain way to be effective. Others are more difficult to use “incorrectly”.
-2 - Single-Point weapons - Picks, spears, syringes. Any weapon that has a single point that must contact the enemy in a specific way in order to deal a decent amount of damage. Also, weapons with difficult attack angles, like scythes, where the damaging part of the weapon is faced away from the enemy.
-1 - Line of damage weapons - Swords, knives, and other weapons that require a solid strike along a particular piece of the weapon, where the weapon can be said to have an attack angle, fall here. Weapons that have point attacks but are still effective without any solid hit, such as a nailboard, would also fall here.
+0 - attack-anywhere weapons - Clubs, pipes, maces, etc, where the weapon will be dealing full damage with a solid blow no matter how it is angled, because every surface is a striking surface.
+1 - Weapons that can still do significant damage even with glancing blows would fall here. Jagged tearing weapons and electric weapons like a stun baton would fall here.

Balance - A measure of how well-suited the item is for being swung/thrust/etc. This factors in both how well suited it is to be handled and overall weight, so light but lopsided items would have ok balance, and very heavy but evenly balanced items would have worse effective balance.
-2 - Very clumsy or lopsided items ill-suited for swinging or thrusting. Characterized by requiring effort just to hold steady. frying pan or pot(a heavy pot, a light one would go down to -1), chainsaw, chair, vacuum cleaner.
-1 - Balance of the object is uneven, but in a way that at least doesn’t interfere with swinging. axes, sledgehammer, rifle, scythe, most polearms.
0 - Neutral balance, neither well nor poorly weighted for the typical use. Heavy stick, rock, pool stick, kitchen knives, claw hammer, metal pipe, crowbar, handguns.
+1 - Well-balanced for swinging or stabbing. Baseball bat, golf club, heavy swords
+2 - Exemplary balance, generally counterweighted somehow. Quarterstaff, light swords and fighting knives, short spears.

In short, no. there’s a difference between a one-time effort to update things and a continuing drag on adding content by having a large number of properties you have to come up with for each new item. If these were specialty items it’d be one thing, but the melee and thrown stats have to be applied for every item, even if it isn’t a weapon, so I’m very resistant to adding more stats. Also what we’ve come up with as guidelines is sufficient for guidelines, but not necessarily for item stats, that would take a whole lot more work, and in the end it would require even more effort to understand the process of translating the stats into effectiveness of the item.

I approve of a “throwable” flag (or set of flags) to differentiate throwing weapons from other stuff.

Perhaps a field that dictates the skill you need to throw a weapon properly? Maybe just as a key-value pair:

Or similar (defaulting to 0 if omitted). For instance, a javelin is certainly an effective throwing weapon, but it takes practice to throw it properly. Meanwhile, anyone can throw a baseball ‘properly’ (even if their aim sucks). Perhaps if you have less than that throwing skill, you take penalties to throwing the weapon (or get a bonus for having it, or both). For any weapons that are not really throwable (blankets) give them a required skill of 99 or some such.

I just noticed you missed the cut damage portion of throwing damage (note, right under the railgun modifier, the integer “dam” is declared, set equal to real_dam as posted in the OP, and modified as seen at the bottom of the following code block to include cutting damage:

        // If there's a monster in the path of our item, and either our aim was true,
        // OR it's not the monster we were aiming at and we were lucky enough to hit it
        if (zid != -1 &&
           (!missed || one_in(7 - int(zombie(zid).type->size))))
        {
            monster &z = zombie(zid);
            if (rng(0, 100) < 20 + skillLevel * 12 &&
                thrown.type->melee_cut > 0)
            {
                if (!p.is_npc())
                {
                    message += string_format(_(" You cut the %s!"), z.name().c_str());
                }
                if (thrown.type->melee_cut > z.armor_cut())
                    dam += (thrown.type->melee_cut - z.armor_cut());
            }

So the following sums up throwing damage:

X = (the weight of the object in grams / 452) + (weapon's bash damage /2 ) + (your character's strength / 2) ) X is capped at (the weight of the object in grams / 40)

Y = (weapon’s cut damage - target’s cut armor)
Y can’t be less than 0

So the damage is X + Y

One thing that strikes me as odd is that the object’s weight and bash damage and the character’s strength are rendered pretty trivial compared to cutting damage, because cutting damage is effectively flatly applied. (Most enemies you encounter don’t have much cut armor, so this reduction isn’t that significant).

Hence, combat knives are not only more useful (as throwing weapons) than “throwing knives”, they also do more damage than iron javelins, despite the fact that they are much lighter. Historically, the weight of iron javelins and similar weapons helped pierce/destroy enemy armor. We should represent this some how to make it more worth while to carry around these bulkier throwing weapons.

I’m not so sure about the skill requirement, what would be the effect of not meeting it, other than poor accuracy etc, which you already have?

I included the cut damage code in my paste, but neglected to add it to my analysis.
I totally agree about weight synergising with cut damage, if you get a solid hit the shaft will make a lot of difference with regards to force applied.

Also while we’re at it, might want a unified system for throwing aids. Right now that means the railgun CBM, but offhand I’m also thinking atlatls and slings. We need a way to match ammo to throwing aid. Ideally you could do wacky things like throw a grenade with a sling.

Perhaps have the throwable flag, and have the value attached to it depict how good of a throwing weapon it is? Similar to how the “chop” and “slice” flags denote how likely a weapon is to stick in a target, with no flag at all meaning very likely. Something like a rock or baseball could have “throwable, 1” to indicate it’s generally an effective throwing item, javelins and shuriken could have “throwing, 2” as they’re specially designed to be thrown, and a kitchen sink wouldn’t have the flag at all, indicating it’s general ballistic crappiness.

I imagine that not meeting the skill requirement would most likely impact the range more than anything else. Throwing a javelin, discus etc properly will send it much further than it would otherwise - whereas a blanket isn’t going more than one square no matter how far you toss it.