Looked at this: http://stackoverflow.com/questions/4925135/how-is-an-rpg-class-hierarchy-to-be-used and http://stackoverflow.com/questions/9961043/what-is-a-good-java-data-structure-to-store-rpg-game-items and I’m implementing a system that has properties as interfaces, so for example an “Iron Sword” will have the properties (i.e. implement the interfaces) “iron”, “melee”, etc. However, if I wanted to randomly generate items like swords with random properties, how would I do this? I don’t think the solution is to make a different class for every single property combination.
Feed the class with possible needs
class Sword <- feed this with melee, [oneHand, twoHand], [iron, silver, etc]
I read the links but it doesn’t make sense to me that Iron would be an interface on its own. You might have a “Material” interface which has multiple implementations (iron, wood, steel, mithril, etc.). This would at least make it easier to mix and match materials: public Sword(Material material) { ...}
.
That’s just example. You could make Iron below Material.
Yup, I was referring more to Jimmt’s comment: “…so for example an “Iron Sword” will have the properties (i.e. implement the interfaces) “iron”, “melee”, etc.”.
I could see melee as an interface because it may result in different behavior from a RangedWeapon or a MountedWeapon. It would be good to be an interface because some weapons like spears could be used as MeleWeapon, RangedWeapon, and a MountedWeapon.
In contrast I see Iron as something that affects behavior but does not necessarily have behavior of its own. You might have a base Material class that has properties for strength, potential sharpness, fire resistance, etc. Then have Iron, Glass, Steel, Mithril, etc as either instances of that class or as subclasses.
One place where this may get complicated is when materials can affect behavior. For instance, Iron is meltable, but wood is not. If players can melt a weapon and reforge it into another one, it may get trickier.
Well, in this case, wouldn’t I just make enums?
Trait composition through interfaces is well and good, but if you’re composing random attributes for objects at runtime, you’re not going to be able to use interfaces alone to do it. The type system is static, so bytecode hackery aside, every type you created at compile time is all the types you have available.
The suggestion to have a Material field on items is a good one, but parameterizing it like Material would be too static. You could I suppose have pre-set materials like Iron, Steel, Adamantine, whatever, but chances are you’ll want to define new materials at some point without having to recompile, so you’ll probably want to make your constructors as powerful as possible. The Builder pattern is really nice for that sort of thing, and should be something you look into.
Hm, builder pattern…so I would have something like this?
abstract class Builder {
public abstract void addProperty(Property p);
public abstract void generateRandomProperties(int foo);
}
class SwordBuilder extends Builder {
Sword sword;
public void addProperty(Property p){
if(p instanceof SwordType){ //swordtype is a subclass of property
sword.setType(p); //maybe p is iron or something
}
if(p instanceof Bar){
p.setBar(p);
}
}
And then having a builder for bow, staff, etc…is this too specialized? Am I doing this right?
I thought about this some more, what’s the specific advantage of a builder pattern?
That approach I think negates a bit too much of the static type system, making a sort of untyped object model that’s checked on an ad hoc basis. Having a dynamically typed runtime might be all right if you’re making a scripting language, but in the end, you want a RPG. Now keep in mind that what I’m suggesting here is just one design, and there’s no One True Way To Build An RPG. So that said …
The idea is to figure out what properties are fundamental, and build everything up from that. Think of it as the difference between class-oriented RPGs with roles like “warrior” and “mage” and classless ones where you have stats like “strength” and “mana” and skills like “axe” and “conjuring”. Want a warrior mage? No problem, put points in the relevant stats/skills for both. Well, the same idea can apply to objects. Don’t want to have separate classes for Pouch and Bag? Just create a single Container class and give it a capacity field. Don’t want people equipping a Chest? Easy enough, just make an “equippable” flag on equipment. Figure that’s too binary and hardwired a concept? Change the concept, make encumbrance a calculated value based on size and weight and hell, balance if you want.
You can go absolutely crazy with fine-grained skills that simulate every physical property from weight to ductility to tensile strength to melting point, but unless your name is Toady One, you’ll eventually aim for fundamental properties that are somewhere above a full blown physics sim
So what this all means is that objects are going to have a lot of properties, and that’s where the builder pattern comes in. I’m going to just present it without any further preamble, but just remember, this is just one possible builder design out of many, and this is just a partial example off the top of my head:
WEAPONS.set("gladius") = new Weapon.Builder()
.name("gladius")
.description("A crudely forged gladiator sword with a nicked edge but a wickedly sharp point")
.quality(SHODDY)
.material(BRONZE)
.weight(1500)
.value(16)
.addDamage(2, SLASHING)
.addDamage(5, PIERCING)
.build();
Note that constants like SHODDY or BRONZE could be as simple as enums or be whole objects with properties in their own right, maybe even with their own builders. You don’t have to care (I’d start simple)
I’m not going to dwell too much more on the builder pattern here, but there’s a few cool things about it: you can easily add new properties, don’t have to remember dozens of constructor args (in fact you’d want to make Weapon’s constructor private!) and you can create “template” builders by setting a few properties and saving the builder somewhere to be completed later.
Just a specific note on code: you should really avoid calling instanceof if you can make polymorphism do the job instead. Until you start getting into network serialization, it’s best to pretend instanceof doesn’t even exist.
Wow, thanks for typing all that out. I’m pretty sure I got it working (with the method chaining you used as an example) and it’s pretty sweet. Thanks!
And then for status effects, you’d do something of the same thing.
Create a couple of base effects, like a EoT (Effect over Time), AoE (Area of Effect), Buff (Stat changing effect), and the like. Write a builder that lets you make several types of them based on attributes/damage types and you can then add them to the weapon before building it. :3
As for finally randomizing it, there are various styles for it, such as making a prebuilt ‘tree’ of possible weapons weapon weapons in the form of: Layer 1 [Weapon Type], Layer 2 [Material], Layer 3 [Quality], Layer 4 (Select Several) [Special Effects]. Then build the base weapon off the first three and dump some number of special effects on it based off Material, Quality and the like. :3
Big thing this statement! Remember that the more detail you add to the RPG the more chance there is for something to be badly broken somewhere and the more work you’ll have to do on balancing. Toady’s famous game (Dwarf Fortress) has had some major game breaking due to the detail that was put into it. Like being able to kill dragons by throwing worms through their eyes and other, worse things.
Beyond the whole balance issue is a Debugging one. If you put in too much detail that actually matters, IE- Iron weapons rusting, certain enemies being killed easier by Iron/Iron based weapons or by Silver, or a major difference in how Slash/Pierce/Blunt damage is handled in your code (Beyond simple subtractive resistances and the like), the more difficult debugging things when someone says “X weapon is causing odd damage” becomes. It can lead to interesting systems, like forming an alloyed sword that has both silver and iron in it (It could be a fantasy alloy since I can’t find evidence) that’s good VS Faerie, Werewolves and Vampires, but unless you really want to spend time making sure that you know how your detailed item attribute system leads to that, it’s probably better not to try.