2
\$\begingroup\$

So I don't even know if this is the right community to ask (as I imagine it's probably quite maths heavy) in but I figure it falls under the realm of game mechanics.

I want to develop a game mechanic that utilises complex D&D style interactions but on another level from that, but I don't really know where to begin conceptually. What I mean by D&D style interactions is each character will have a set of attributes, strength, skill, intelligence etc and those attributes will dictate how interactions play out between characters.

So for basic example, two characters battling each other and each attribute ranges from 0-20.

Character A - Attack:13, Defence:14 Character B - Attack:15, Defence:10.

So when Character A strikes at Character B I need to calculate how successful that attack would be and what the outcome would be, which would then feed back into their attributes. So maybe their attack is semi-successful and produced a flesh wound, not enough to kill but that reduces Character B's Attack attribute to say 13.

Now that's a fairly trivial, example where I want to try and take it to the next level is to introduce combined attributes that all have an impact on the outcome of a move. So Skill, Experience, Fitness, Attack Speed, Anticipation and even Luck (which I figure would be randomised and offset by attributes like Experience).

Ideally I'd like to build an engine where I can define attributes and how they interact and can add more over time to build up the complexity of interactions. But I am at a loss where to begin. I'm not looking for a ready made solution but just to be pointed in the right direction.

To add some further explanation as to where I'm struggling. Are there known algorithms, techniques or maths solutions that are used to calculate attribute based interactions? In my head I'm imagining some system of values and weights with some pseudo-randomness thrown in but I'm at a loss as to how you actually calculate outcomes.

When I try and think it through all I get is a massive set of 'if' statements where values go in at the top, if's are applied and modify the outcomes. So...

If CharA_Attack == 15 and CharB_Defence = 10 Then Outcome = Kill

If CharA_Speed == 10 and CharB_Speed = 12 Then Outcome = Deflected Blow

If CharA_Luck == 14(random) and CharB_Luck 7(random) Then Outcome = Flesh Wound

Etc...

\$\endgroup\$
  • \$\begingroup\$ It's unclear to me what specific problem you need help solving here. If you need guidance in designing your attributes, it would help to establish your goals first, then see how those steer your design decisions. There's a good example of this in Gods and Dumps: Attribute Tuning in Pillars of Eternity. If your problem is in how to implement this attribute resolution engine, it would help if you edit your question to articulate one specific implementation problem. We usually can't answer "how to get started" so be specific. \$\endgroup\$ – DMGregory Aug 2 at 10:48
  • \$\begingroup\$ @DMGregory Yes, looking at it now I wasn't very clear. I will update to try and clarify. \$\endgroup\$ – David Aug 2 at 10:52
  • \$\begingroup\$ "Are there known algorithms, techniques, or maths solutions that are used to calculate attribute based interactions?" Rule books for tabletop RPGs and war games are absolute tomes of such techniques, so I can't imagine you've had trouble finding them. But you probably don't want to implement every attribute resolution algorithm ever, just the one your game uses (eg. the D20 opposed roll mechanism of success = (RND(20) + skillModifiers > RND(20) + difficultyModifiers)). So, first decide on your mechanisms, then design the system to implement them. \$\endgroup\$ – DMGregory Aug 2 at 11:08
  • \$\begingroup\$ Type "sigmoid function" in the search bar for a lot of relevant discussion. \$\endgroup\$ – jhocking Aug 2 at 12:23
  • \$\begingroup\$ "If CharA_Attack == 15 and CharB_Defence = 10" - it should probably be something closer to "If CharA_Attack + X > CharB_Defence" or "If CharA_Attack / (CharB_Defence+1) > X". But there are many possible formulas. If you're not looking for a ready made solution (which is probably off topic here anyway), you'll probably need to spend a lot of time in Excel or playtesting to figure out what formulas would actually make sense, and maybe starting with only 1 or 2 attributes and then adding more once those make sense. Although ready made solutions can provide a good starting point or inspiration. \$\endgroup\$ – Bernhard Barker Aug 2 at 12:31
4
\$\begingroup\$

This is sort of an open-ended question, but I will try to offer you some guidance on where to begin.

When I try and think it through all I get is a massive set of 'if' statements

Yes, not ideal. What I think you want here are weighted values between 0.0-1.0, weighted and combined through multiplication to a result in the 0.0-1.0 range. This is a way to represent falsiness (0.0) vs. truthiness (1.0) without being stuck with binary decisions as such. Google weighted averages for more.

For example, let's say two swashbucklers are fighting a duel. With light swords such as foils, speed and the ability to quickly perceive what your opponent is doing (wit, intellect) are crucial. Let's say A strikes at B:

float attackStrength = (A.speed * 0.8) + (A.wit * 0.2)
float defenseStrength = (B.speed * 0.6) + (B.wit * 0.4) //a little more wit, to see what your opponent is doing

You could also include each combatants footing, from the last attack / defend sequence:

float attackStrength = (A.speed * 0.5) + (A.wit * 0.4) + (A.footing * 0.1)
float defenseStrength = (B.speed * 0.5) + (B.wit * 0.2) + (B.footing * 0.3)

The weights are those constants you are multiplying by, e.g. 0.5. These denote the importance of that term in resolving the equation in question.

And then

bool outcome = attackStrength > defenseStrength; //or you could make bool a float, too!

Formulae can be as simple or complex as you need them to be. Just ideally keep each term in this 0.0-1.0 range or you will get confused.

You'll notice that the weights on each line always sum to a maximum of 1.0. This is required so that the maximum resultant value can be 1.0 * 1.0 = 1.0. A similar requirement applies to your stat variables. Let's say your wit, speed and footing are all in the range 0-100 (max), you then just need to divide each one by the max, so a very high stat value of 100/100=1.0. Obviously then, there will always need to be some form of maximum value...

...However this doesn't necessarily mean your characters reach a hard limit in terms of capability. One way to achieve that is to use a non-linear curve that drops off as skill goes higher and higher - it is tangent to some value but never quite reaches it (indeed, Math.tan()gent could work with some fiddling). This just ensures that you can keep pushing the stat in question, for infinite levels, but you will never reach a cap in terms of the effectiveness it produces.

The benefit to using 0.0-1.0 range for everything, both terms and result of each equation, and the final result, is that you always know what you are looking at: for example, a value of 0.8 is always going to be closer to true than the false, by a good margin.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ What you are describing sounds exactly like what I'm looking for, I guess the arbitrary part that I'll have to figure out is what weights have what importance to try and achieve the right balance. I'm not actually worried about characters plateauing, in fact I see that as a good thing as in real life you do eventually reach a stage where you're as good as you're gonna get and improvement is diminishing returns. \$\endgroup\$ – David Aug 2 at 20:48
1
\$\begingroup\$

There is a python-library called Lea that is made for doing calculations like that (or "working with discrete probability distributions in an intuitive way. It allows you to model a broad range of random phenomenons, like dice throwing, coin tossing, gambling, weather, finance, etc. More generally, Lea may be used for any finite set of discrete values having known probability: numbers, booleans, date/times, symbols, … Each probability distribution is modeled as a plain object, which can be named, displayed, queried or processed to produce new probability distributions"). One of the examples, called RPG Combat, shows how to calculate possible outcomes of D&D-style attacks (D20+attack vs defense, with a chance of critical hits): https://bitbucket.org/piedenis/lea/wiki/Lea3_Examples#markdown-header-rpg-combat

It should be possible to expand on that to create a more complex combat system with more attributes and possible outcomes, then query the resulting models for various statistics and draw graphs etc.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.