clintbellanger / flare

Free Libre Action Roleplaying Engine
http://clintbellanger.net/rpg/
GNU General Public License v3.0
166 stars 41 forks source link

Loot Table redesign #718

Closed clintbellanger closed 11 years ago

clintbellanger commented 11 years ago

Currently there are several "hardcoded" things about the loot table that need to be made configurable.

Don't start coding a solution until we agree on specifications! Let's consider how various game designs might want different ways of handling loot.

Side note: For now I'm still in favor of fixed items (a large items.txt file) instead of random rolled loot (random affixes applied to random base items). But base items and affixes are something we will add later, e.g. in Wandercall or for Flare 1.1 or so.

pennomi commented 11 years ago

While work on this issue is happening, there's a lot of hardcoded things about ITEMS as well, for instance some attributes, (like Absorb) can only be put on certain item slots.

makrohn commented 11 years ago

I know for Polymorphable, where item levels don't currently matter, being able to allow an arbitrary number would be awesome. I think I'd like to be able to, within an enemy file, define the loot similarly to how I would with an event, with a loot table to fall back upon if it's left empty. "loot=level,1,1" to drop Level 1 loot, or "loot=level,1,5" to drop loot somewhere between levels 1 and 5. In combination with "loot_chance" this would work fine for Polymorphable. I know other games might want something even more configuable, in which case it might be handy to put loot and loot_chance together in multiple lines. "loot=level,3,7,35 loot=1,1,50 loot=currency,5,10,75" would mean that, when defeated, an enemy would have a 75% chance to drop 5-10 gold, AND a 50% chance to drop something level 1 AND a 35% chance to drop something between levels 3 and 7.

makrohn commented 11 years ago

Wit the above example, there's still 13% chance it'll drop 3 things, and an 8% chance it'll drop nothing, which I think keeps it interesting.

wokste commented 11 years ago

I like the idea that you have tables for each group of items. I can think of: currency*, magic, melee, ranged, potion and scroll. (of course, they may be different at the end) On thing I like to see is dropping specific items. This can be useful for quests etc.

makrohn commented 11 years ago

You can already do that for quests, actually. Look at https://github.com/clintbellanger/flare/blob/master/mods/averguard/enemies/professor_langlier.txt#L13 which defines quest_loot=(don't drop until this point in the campaign),(don't drop after this point in the campaign),(item ID#)

stefanbeller commented 11 years ago

So what does a drop actually depend on? Here is my opinion: It doesn't matter how strong the hero is, but only which kind of monster was defeated. And maybe where it was defeated. Of course some randomness would also come handy.

So to put it in a formula, I'd go for

roll a dice if any loot // should there be a skill to passively increase this chance?
// dice is dependant on mob, map (and hero)

itemlevel = monsterlevel + maplevel + randomness (+- 3)
// on some maps, all the monsters are harder to defeat, so they yield better items.
// Think of it as a real evil place.

// from the itemlevel we need to derive the number of items to be dropped:
// so for a itemlevel of 5 we could drop a valuable level 5 item, or instead two items having level 2 and 3,
// so maybe one item at full level with probability 3/6 = 0.5, two items with 2/6 = 0.33 and 3 items with 1/6=0.16

foreach item:
  itemclass = one out of the possible itemclasses for that monster and map.
  // (mages dropping mage loot, goblins dropping worn off clothes)
  // maps usually don't have itemclasses assigned, but special place such as the
  // averguard prison map drops additional rusty hand cuffs ;)

  find this item in the loot table 
  // itemclass must match, level should match.
  // if there is no appropriate levelmatch take a lower base item, and add more magical attributes later on.

  // Now we need to determine the quality of the item, i.e. base damage, magical attributes.
 [not sure]

So I would object @clintbellanger and propose a system, which already calculates attributes depending on the situation. I admit this is a little more complex as the unique items must be handled and stored and a lookup of just the itemid is not sufficient any more. Maybe I am just thinking too longterm.

In the items.txt it might look like as follows:

[item]
id=51
name=Cheerful Clothes
level=1
quality=low
type=body
icon=112,16
sfx=cloth
gfx=clothes
loot=clothes
price=3
stepfx=cloth
class=goblindrop
bonus=HP,2 // standard bonus, so definitely add 2 to HP
// now additionally defined attributes:
addbonus=5,HP regen,1,3,5, of Joy
// This bonus is added with a probability of 5 percent, it adds 1-3 points to 'HP regen' 
// for each point added increase prize by 5. If this bonus is added, 
//display name with additional string ' of Joy'

addbonus=3, HP,1,5,7, of Life
// add 'HP' bonus of strength 1-5 with a probability of 3 percent. 
// Increase prize with each added point by 7
// If this bonus is added, the name gets ' of Life' amended.
clintbellanger commented 11 years ago

The current loot algorithm for reference:

Item level tables are currently done in a weird way, it can be rewritten with this config pass.

Think of a loot table like this. It's similar in design to e.g. D&D loot tables:

Level 4 gear. Roll 1d100
1 = Epic Sword
2 = Epic Staff
3-5 = High Sword 1
6-9 = High Sword 2
10-12 = High Staff 1
13-15 = High Staff 2
16-25 = Sword 1
26-35 = Sword 2
36-45 = Sword 3
(etc)

One problem with this implementation is that the loot chances are affected by the number of items of each category at that level.

A better method would be to make several rolls:

If we did random affixes, the list would expand:

Affixes

If we did random item affixes, we'd do it this way. Think of it like database tables:

There are base items and there are affixes (bonuses that optionally add to the name of the item, e.g. "of the Eagle"). Items can have multiple affixes, and each affix fix on several items, so it's an M-N relationship. We use a third table to connect base items with possible affixes. These three "tables" would be three different files in the /items/ folder.

ItemStack would be expanded to include the rolled affix information for items.

pennomi commented 11 years ago

Now I'm not saying we should do random items instead of tables (but it would be cool if we did!), but I imagine a different way of doing that than what @stefanbeller proposed.

Think instead of having a item_modifiers.txt file that determines what possible modifiers are available (and what base item types they can be applied to). We'll still need an items.txt file to create those base items (and plot items of course). With the extra config file, it becomes open to modders to add new item modifiers at will to all applicable items.

The way Diablo 2 does its prefix/suffix system is by not actually storing the item itself, but by storing the random seed that generated the item. Diablo 3 (iirc) actually stores all of the random attributes in the item save itself (actually on the server to prevent duping). If we did a prefix/suffix system I think a method like Diablo 2 would be great. The main flaw I see with that is if someone added an item modifier in a mod, it would mangle all of the existing items in saves since the algorithm could resolve differently.

stefanbeller commented 11 years ago

@pennomi Yeah I was thinking about that as well. So storing only a seed to derive the random attributes. I am not sure which way would be a good way to go for making sure to have no such changes when modifying the modifier files.

1) it just breaks, but we declare it a feature. Somebody who is interested in modding may just 2) use different parts of the seed for different parts of the modifiers. Also just discard random numbers when they are out of range instead of doing a modulus on them.

clintbellanger commented 11 years ago

There's a philosophical side to random loot that I want to discuss.

I think it's quite possible that random loot is bad, shallow design. And people only like it because it's addicting, like slot machines.

In games with random loot, the best items tend to be specifically designed anyway. You know you'll be upgrading that Prefix Staff of Suffix for a named epic with mostly set stats.

A limited, hand-crafted loot list lets the designer give thematic loot to creatures. Skeletal soldiers only drop bucklers or short swords. If you want to collection mana potions before taking on a boss, go clean out that map full of goblin herbalists.

But there are engine considerations: if we want our action RPG engine to be useful, it probably should support random loot in the prefix/suffix style?

stefanbeller commented 11 years ago

Well I agree that it makes sense to have only certain types of loot for certain mobs. But do you want to find always the same buckler dropped by the Skeletal soldiers? I would find it more interesting if I could find at least 30 different bucklers dropped by skeletons. The better the buckler is, the more unlikely is the drop chance of it.

So maybe I'd go for a static designed handcrafted loot table, but having way more items. As of now there are 590 items in the fantasycore items.txt, but I'd expect to have 30k items in there. It's clear one cannot simply write down 30k items by hand, so I'd try writing a script for it. That script would get some information like: "Buckler, Skeleton" and a list of modifiers applicable to these items. It would generated a huge itemlist, which can be finetuned during a testing phase.

clintbellanger commented 11 years ago

There are great games that use a small amount of loot, fixed per creature. Great recent example: Dark Souls. Great older example: the 2D Castlevania games.

The chance for loot to drop is reduced. It generally makes cash more valuable, and makes specific treasure placed on the map more interesting (e.g. the first time you loot a specific chest there is a specific item).

Dark Souls additionally makes equipment upgradeable (e.g. adding +1, or adding fire damage). But that's a separate feature.

pennomi commented 11 years ago

The issue with the way we currently do loot, in my opinion, is that it mimics the 'random loot' paradigm without having the sheer volume that makes that kind of loot fun.

Another issue is the way we have some loot that does little to nothing - ie. normal Boots. They really have no use but to sell.

I'd really like to see a hand-crafted set of loot for Flare's first game. I'd say that each item type should have one of two or three associated 'perks' and we make the items around those. So for swords, I'd say the three perks we could build items off of would be 'damage' and 'block' for mundane items and 'lifesteal' for magic items. For axes (would it be hard to add those?), maybe 'crit,' 'damage' and 'bleed.' For boots, 'defense,' 'speed' and 'teleport.' Just throwing ideas out there.

Also, blue items should be (possibly overpowered) unique items that have huge bonuses. Like a 75% fire resist cloak. Or a bow that shoots triple shot for its main attack. Maybe our current fire/ice bows would fall in this category too. The way I look at it, a blue should be so special that you're unlikely to get rid of it for many levels, and completely unique rather than just a beefier version of the green item.

stefanbeller commented 11 years ago
  • ie. normal Boots

I consider them as good starting equipment,

clintbellanger commented 11 years ago

Language-related question:

Imagine we create an affix file that we can use to randomize loot. Example:

[affix]
type=prefix
name=Dwarven
bonus=HP,5

[affix]
type=suffix
name=of Accuracy
bonus=accuracy,10

[item]
name=Clothes

If we combine these, we use Prefix + Space + Base + Space + Suffix to get "Dwarven Clothes of Accuracy".

Will this logic be valid in all languages? It seems like it won't work, as some languages prefer compound words to phrases like this. So we could respect whitespace (e.g. put a trailing space as in "Dwarven "). But that wouldn't account for capitalization if we need one word, e.g. "Zwergenkleider" in German. In such cases, can we always just say "Zwergen Kleider" and it would be acceptable?

Are there any languages where this "Prefix Base Suffix" formation completely fails?

makrohn commented 11 years ago

Speaking of German, I'm more concerned about gender issues. Adjectives will get a different ending depending on the gender of the noun, like the plural clothes, or the (likely masculine) sword. So, there's a problem with the prefix alone.

In French, you're going to need Base Prefix Suffix, I believe, but I know little about French.

In Japanese, it'd be... thinks a minute ClothesのDwarvenAccuracy (BaseのPrefixSuffix). But hey, no plurals to worry about?

clintbellanger commented 11 years ago

Yikes, I didn't think about noun gender. And different languages might have different genders on items, right? So we probably couldn't give each base item one gender.

Hm. I'm not sure if we'll be able to build these names correctly at runtime. If we did, it could require lots of special code and data per language.

Obviously with a static, short item list it's not a problem, because the whole item name can be translated (as we currently do).

clintbellanger commented 11 years ago

Imagine what it would take to do randomized item translations correctly:

Maybe there a few broad language types that share many rules (germanic, romantic, etc) so perhaps there's not special code for every single language, but still.

As @makrohn said in chat: I have a whole new appreciation for Diablo 3 now.

Hmm...

Not only would this be hard to create, it would make translation duties far more complex.

So we should consider other systems:

igorko commented 11 years ago

Migrated to clintbellanger/flare-engine#123