Designing an efficient, scale-able weapon stats system

Hi all, I’ve been thinking about creating a game with several weapons of different types that all share some properties, but have perhaps one property that only belongs to a certain weapon. I like to structure my projects before committing a lot of time to creating assets and balancing gameplay, etc. I have never taken on a project like this before and I’m struggling to figure out how a system like this should be built from scratch.
I’d like to have an efficient (fast) system that can store weapon statistics based on the name/Id of the weapon (Shortsword, Staff, etc.) that can then display the statistics about a weapon, like on an overlay when the user hovers over a specific weapon in their inventory, in a shop, trade window, or anything.

This is simply a proof of concept of what sort of things I have in mind, treat it as pseudo-code.

Shortsword = {
	["Damage"] = 10,
	["AttackTime"] = 5,
}

Longsword = {
	["Damage"] = 15,
	["AttackTime"] = 6.5,
}

Bow = {
	["Damage"] = 10,
	["AttackTime"] = 5,
	["ReloadTime"] = 4
}

Warhammer = {
	["Damage"] = 20,
	["AttackTime"] = 15,
	["Abilities"] = {
		["Slow"] = {
			-- Slow target by 50% for 5 seconds
			["EffectDuration"] = 5,
			["SpeedModifier"] = 0.5
		}
	}
}

As you can see, every single weapon shares a Damage and an AttackTime property, but only the Bow weapon has a ReloadTime property. The Warhammer would have a special effect with custom properties in addition to its normal attack, while the other weapons have one general attack.

I have two ideas for this that I honestly haven’t put a whole lot of thought in to (that’s why I’m here!).

  1. One method seems easiest but not very ‘clean’ or scale-able, and that would be to store each relevant stat in a BaseValue like StringValue WeaponName, NumberValue AttackTime, NumberValue Damage, etc. and only include the stats pertaining to each weapon (the “Sword” would not have a ReloadTime or Abilities values). My only hesitation with implementing this method is that this seems like a lot of creating and organizing values for each new weapon I want to add to the game, and it won’t scale very well if I ever decide, "hey, let’s add a durability stat to all of the (100+) weapons!'…
  2. Another method I can think of (may not work because I’m not very comfortable with tables/metatables yet) is to attempt to have a ‘Master’ table of all possible weapon stats (Damage, AttackTime, etc) and attempt to __index them for every weapon when requested. If the value (stat) doesn’t exist for said weapon (trying to access a Dagger’s ArrowSpeed for example), return nil or something? Again, I’m struggling to explain this because I don’t have a lot of (or any) experience with meta-tables. This sort of solution also runs into the same kind of problem as before with adding additional stats, though maybe not as drastic as the first idea.

A third idea that I’m currently against is a combination of both of the following ideas, only making a table for the properties that every weapon has, and using BaseValues for individual properties. I don’t like this idea much and don’t expect it to be the leading or sensible solution, so I won’t go more in depth into it.

Any resources, ideas, or feedback would be greatly appreciated here! I’m going to say thank you in advance because I won’t be around to view this post for ~8 hours after posting it. Unfortunately this also means I won’t be able to reply to any questions/confusion for a while. Hopefully this post makes a bit of sense, and thanks again to everyone who can offer advice! Thanks for reading!

8 Likes

You might want to look into OOP as your description seems to fit in with the code reuse facilitated by that tech.

This is a problem encountered by many developers along their path to make a successful game. The best solution for this problem depends on the developer - all developers are different and have their own preferred way of solving a problem.

For a more linear system,
I’d suggest to take a look at an Entity Component System. Following this design archetype, there is no individual classes for each weapon, and instead they have each many “components” that can be set and retroactively update, even when the game is running. That allows for custom weapons to be generated on runtime, which shows off the versatility and expandability of this design.

This is more or less a merge between your first and second idea. In order to add a new statistic to a weapon, you’d have to design it out in your system element and then add the component to each of your weapons, though I suppose that can be negated if you make a master entity builder.

When you try to index a statistic that doesn’t exist, it would be best to throw an error. That way, it’s much easier to catch errors in your code. If you expect your entity component system to be indexing values that aren’t there other than to check if it exists, then chances are you’re doing something wrong.

However, problems arise when you try to make something much more complex. If you’re looking for a way to quickly add new features on the fly, and even completely new weapons, it’d be better to simply have a module for each weapon and have a master controller call those modules to handle anything.

For example, if you have a system built for exclusively swords, and you decided you wanted to add in a bow, you’d have to add loads of components just for that single bow. Going down to the basics, Lua is a scripting language that allows for quick modifications. If you wanted to have a highly versitile weapons system with each weapon having unique effects, it would be a waste of time to code in a component for something that you’re only going to use once.

In that fasion, it would be best to have a low level framework set up that simply calls the modules inside of a folder which handle the hit detection, damage, special effects, etc. with a “Util” folder that contains commonly required features, such as a radius hit detection. Sure, if you wanted to add a feature to all of your weapons it would be a pain, though adding a new unique weapon would be much quicker.

To wrap things up, here are the pros and cons of each method:

Entity Component System

  • Pros
    • Allows quick additions of similar weapons
    • Can be retroactively changed on runtime
    • Allows functionality changes across the board for all of your weapons
  • Cons
    • Slow to add entirely new weapons types
    • Slow to get working (when compared to the weapon module scripting)

Module Scripting

  • Pros
    • Really quick additions of new weapon types
    • Can copy + paste to add a new weapon
    • Quick to get working
  • Cons
    • Updating a stat universally is a pain
    • Is much more rudimentary than an entity component system
10 Likes