flareteam / flare-engine

Free/Libre Action Roleplaying Engine (engine only)
http://flarerpg.org/
GNU General Public License v3.0
1.11k stars 187 forks source link

Random item generation #1815

Closed dorkster closed 1 year ago

dorkster commented 2 years ago

These are some of my current thoughts on implementing this:

WithinAmnesia commented 2 years ago

Can you give some examples of how this would play out / look like? P.S. What are your inspirations / goals for this feature?

WithinAmnesia commented 2 years ago

Also is this optional like it can go along side what already exists; like an optional feature?

dorkster commented 2 years ago

It would have to be optional, since there are plenty of items that don't need the random treatment. Basically, if an item lacked a reference to a randomizer rule file, the item would work exactly like the existing items. The seed and item levels will be saved as zeroes to indicate this.

Having this sort of item generator would give us a way to create level-scaled loot. This is the missing puzzle piece now that we can have level-scaled enemies.

Here's a prototype of what the rule file could look like:

# The level section will only be used when generating a new item. 
[level]
# This line will tell the generator where to source the starting level from.
# Possible values would be 'base' and 'hero'.
# The former being the base item's level, the latter being the player's level.
level_src=hero

# This defines the min/max level offset based on the source level
# In this example, let's say the player's level is 5.
# The following line means that the generated item will be between levels 3 and 8 inclusive.
level_range=-2,3

# The quality section lists chances for the item to be of a certain quality.
# It also defines the min/max number of bonuses for a given quality.
# The format is: quality=<id>,<chance>,<min_bonus>,<max_bonus>
# The chances work like loot drop chances. If a random roll is less than or equal to the chance,
# the quality will added to the pool of qualities to pick from.
# Let's say that the chance roll is 5. In the example below, the item will either be 'high' or
# 'epic' quality.
[quality]
quality=high,100,2,3
quality=epic,5,3,4
quality=rare,0.5,4,5

# The bonus section describes the possible bonuses that the random item can have.
# The format is: bonus=<stat>,<min_value>,<max_value>
# Items will only be able to have one bonus per stat.
# So in this example, the item will max out at 3 bonuses (crit, hp, fire_resist),
# even if its quality allows for more.
[bonus]
# Using the 'bonus' property, it's possible to have a bonus that's not affected by item level.
# So no matter what level the item is, it will gain a 2-5% critical hit chance if this bonus is selected
bonus=crit,2,5

# And this would give a 25 HP bonus
# Note that this will get combined with the bonus_per_level line below because they both use the 'hp' stat
bonus=hp,25,25

# On the other hand, 'bonus_per_level' will scale with the item level.
# Let's say our generated item level is 4.
# That would mean our potential bonuses are 225-325 HP and 8-12% Fire Resistance
bonus_per_level=hp,50,75
bonus_per_level=fire_resist,2,3
Danimal696 commented 2 years ago

Looking quite nice, I think you are sucessfully covering all bases. Just some questions:

So in this example, the item will max out at 3 bonuses (crit, hp, fire_resist), even if its quality allows for more. Meaning that a 3 bonus item can be an upper end "High(2,3)" or low end "Epic(3,4)"?

Next would be if "bonus" would be universally chosen from a list of all possible bonuses or restricted by a user defined list of bonuses per item?, since it would be strange for a ring to hold a "Stun chance%". Or in my case I have a special item type called "Runes" that hold user combat powers and I would like for it´s drop level to change with user level; like"summon rat". So it would give a way to tailor user-made items pre-creation, say special potions (below) or Enchant stones. Maybe it could also be used for potions to have "Powers" generated on the fly, resembling those of Path of Exile, i remember WithinAmnesia managed something like that. Resuming my point, a way so users can create their unique item category by using their own list of bonuses which may not include pre-existant ones (like resistances).

Another thing you hypothesized would be socketable items, that opens the way to have gems of different qualities to drop and a way for the player to fuse them into higher quality with something like a Horadric cube.

An universal item rule, useful for recipes, say, I want my "Summon rat" Lv13 to be able to be combined with an "Electric core" to create a "Summon Thunder rat" Lv13; as you know right now all combinations have to be declared beforehand, so this would mean to create a recipe for each single "Summon rat" item level to cover every single case of combination which is a total hassle, multiply that by as many monster variants you want and then by as many "Summon monster" types. Total madness. So it would be a rule that says all "Summon rat" + "Electric core" = "Thunder rat" indistinc of levels.

dorkster commented 2 years ago

Meaning that a 3 bonus item can be an upper end "High(2,3)" or low end "Epic(3,4)"?

Yes. The item would be able to have up to the number of defined bonuses, but not more. So in our example, it would be impossible to have an Epic item with 4 bonuses because there just aren't that many to pull from.

Next would be if "bonus" would be universally chosen from a list of all possible bonuses or restricted by a user defined list of bonuses per item?

The latter. We'd want to have the ability to restrict certain bonus types to certain item types. For example, weapons might only have damage bonuses, while armor would have absorption and elemental resist bonuses.

Another thing you hypothesized would be socketable items, that opens the way to have gems of different qualities to drop and a way for the player to fuse them into higher quality with something like a Horadric cube.

I mainly brought that up to demonstrate what could be accomplished by changing the way we format inventory/stash item storage in save files. Such a change would have been necessary if we decided to save the entire item definition for generated items. The item generation approach I detailed here doesn't require this change and would remain fully compatible with existing saves. However, it may still be worth making the shift to prepare for things like socketed items. I imagine it would look something like this:

[item_storage]
slot_index=...
item_id=...
quantity=...
random_seed=...
random_level=...
WithinAmnesia commented 2 years ago

'Enchant-able' / socket-able items? Or will Flare have to use a sort of system where a game developer has to just have a sort of quest / crafting system with an exhaustive pre-defined list of all possible combinations behind the scenes (Like tens of thousands of possible combination entries)?

WithinAmnesia commented 2 years ago

Not exactly related but are ~'Arbitrary Skill Levels' able to exist in Flare (Like 166/300 Blacksmithing or Alchemy or Cooking etc.)? A famous example would be like RuneScape skills https://oldschool.runescape.wiki/w/Skills and or WoW's weapon skills https://classic.wowhead.com/guides/classic-wow-weapon-skills and or Classic EverQuest https://wiki.project1999.com/Skills )?

Also is Flare even able to have weapon skills that kind of work like bonus to hit or increased critical hit chance per a certain type of arbitrary weapon type etc.? Examples as in A.D.&D. 2nd Edition [never mind those source books are far too nerdy / basically stupid or complex for complexities sake], Non-Enhanced Edition Baldur's Gate and Icewind Dale have better examples https://lilura1.blogspot.com/2019/07/Baldurs-Gate-Baldurs-Gate-2-Weapon-Proficiency-Tables-True-Grandmastery-Nerfed-Grandmastery.html .

I am not even sure if Flare could support a type of ~'arbitrary weapon skill' system or what that could kind of look like (hopefully not too contrived / just plain stupid [I could not find an ancient WoW machinima about a Tauren going to Undercity to learn swords and the Forsaken weapon skill trainer being paid by the Tauren and saying like 'hold handle and put the pointy end up.' and then the Tauren being angry for it was so self evident but the game forced him to travel around the world and pay some random guy in order to use an item type that should have been accessible from the start] / power-creep enabling )?

dorkster commented 2 years ago

Or will Flare have to use a sort of system where a game developer has to just have a sort of quest / crafting system with an exhaustive pre-defined list of all possible combinations behind the scenes (Like tens of thousands of possible combination entries)?

No, that would be insanity. A hypothetical implementation of socketed items in Flare would simply store a list of the 'gem' item IDs on the base item. Then any bonuses on the gems would be applied to the base item.

Not exactly related but are ~'Arbitrary Skill Levels' able to exist in Flare (Like 166/300 Blacksmithing or Alchemy or Cooking etc.)?

Those sorts of progression systems is not something I've ever considered adding to Flare. It's always felt like something better suited for MMOs (as evident by your examples). As a single-player example, I guess the leveling system in the Elder Scrolls games is also of this type. Either way, I don't think it would be a good fit for Flare.

WithinAmnesia commented 2 years ago

Didn't D3 (I know PoE does) have ~'crafts-people'? As in who a player can ~'unlock' / get a ~'house' / base and then have / collect the crafts-people and have them 'level up' / get better / get more recipes / build / get a bigger 'forge' / crafting world object-thing. As in that kind of system feels like player crafting in that it effectively acts like leveling up a crafting skill but it is not directly the player. Nor like 'you crafted x101 Crude Bronze Dagger for 420 blacksmith experience, ding; you are now 69/150 level in blacksmithing'.

As like in history a Castle would have a blacksmith building inside the walls and a kitchen and other profession buildings (candle-making ftw) and the Lord did not directly craft anything (because they go to war / run the show / have other more exciting things / responsibilities to do; in theory) but could set up the crafting infrastructure / commission work.

In Baldur's Gate this is done with the blacksmith in a town when a player can get a special bug chitin / body parts and then work out a deal with the smith to craft armour for a fee and a time delay: https://baldursgate.fandom.com/wiki/Taerom_Fuiruim

WithinAmnesia commented 2 years ago

I guess item ~'enchantments' / ~'item augmentations' could just be reskinned / rebranded gems like in Diablo II. Same thing in the end but reusing mechanics and could act to steam-line / not get too overly complicated for no good reason.

Also I think Harvest Moon and Stardew Valley don't have (a) direct farming skill(s). As in like 206 / 300 seed planting or 27 / 75 chicken raising or 106 / 150 wood chopping. Yet they both have like (a) non-changing game world(s) then a separate small 'player property' that can have crops and and game objects removed / altered for a general feeling of overall 'farming progression'. Also they use a time / season cycle system would I think is probably overkill / not needed in Flare. Diablo 1 Tristram had that not-quite day, not quite night 'dusk' for it in part subtly invoke a feeling impending doom / night demons.

I don't think having a billion skills is necessary in some games yet having the spirit of professions ~'would be nice' (yet feature creep is not nice lol XD) but like Baldur's Gate the player does not need to be a 'blacksmith' to feel like they are progressing in a sort of blacksmithing way / to make items from their adventures.

WithinAmnesia commented 2 years ago

I think the Diablos have a system of gambling vendors that kind of act like random item generators at the cost of in game resources; almost like a sort of crafting. I guess something similar could be made with this random item proprieties generation system where raw resources go in / get traded (via a dialog / repeatable quest option?) and then a random property (or semi-random range of properties) item is provided to the player / is 'generated'. Something like that or even a 'loot box' item (flavoured as ~'Hand-wrapped weapon' or something) that contains a pre-defined loot table could work like that too I suppose; but with possibly less moving parts / complexity / range of options in some areas.

WithinAmnesia commented 2 years ago

So @dorkster Flare and ~'socket-able' items? Is this even do-able / worth it? Or is this effectively kind of feature-creep?

I suppose if it happened (somehow) that it could be repurposed for ~'item augmentations' (like ~'enhancements' ['Fire Brand' / 'Fire Rune' +2 ~fire damage or something] ). Would this even be possible or it is kind of just not really do-able?

Are socket-able items sort of kind of related to your idea of Random Item Generation property storing mechanics / ~'new ways of storing extra random item property values' or are these things kind of separate?

dorkster commented 2 years ago

Adding sockets to items was simply an example of something we could do if the aforementioned changes are made to the way item storage is handled in save files. I don't want to write it off just yet, but I'd say it's a bit on the "feature creep" side as it stands.

It also has nothing to do with random item generation, so it's a topic for another time/thread. Let's keep this discussion focused on just random item generation.

WithinAmnesia commented 2 years ago

https://classic.wowhead.com/item=15221/holy-war-sword So is this more of the fate that we should be talking about for Flare? Random Stat Value Items like this? Or like what Diablo II does with almost every magical/rare/set/crafted/unique/runeward item?

dorkster commented 2 years ago

Yes, that's a good example of the type of item this system would be able to create. The only exception being there'd be no prefix/suffix added to the item name so we can keep localization simple.

WithinAmnesia commented 2 years ago

@dorkster Can items retroactively gain more attributes / stats (random or fixed values +1 X or +1-3 X) with this system / idea? Or is a case where every stat generated is only at item generation / creation?

P.S. I realized that there might need to be an if check / gate to not have an items that are over stacked with added stats. Although I suppose if items (somehow) have a stat limit (or something like a stat limit) that could also potentially be a solution to having over stat stacked items. I wonder if an item had a status like, or maybe a check like for a base item.

Would this make any sense to have on items? item_augmented=0 (or =1)

Then somehow if item_augmented=0 then stats can be added retroactively or item_augmented=1 then stats cannot be added retroactively?

Or is this missing a point? I am taking my best guess / stab at this. I am not sure what would work or not work exactly with Flare.

I guess I am wondering how to add to items without exhaustively making by hand ~10,000+ manual base item + item augmentation combinations. Yet simplicity seems to win out; who needs complexity for the sake of complexity? I don't know all of the details / everything. This kind of feels like Depth verses Feature Creep. I think that your idea (Random Item Generation) is good but I keep thinking about how to augment items for it would add a lot of depth. Yet I am not sure how to do that without tons of added complexity. What do you think about all of this?

Danimal696 commented 2 years ago

A way to empower existing items would be pretty cool, like upgrading to player level or adding more bonuses

dorkster commented 2 years ago

I think it would be best to start by keeping it simple and not allow item modification beyond the initial generation step. Such an augmentation system could work in theory, but I'm not sure it's something I'd want to add to Flare.

ate088 commented 1 year ago

Just read this discussion and wish to chime in with my opinion on socket-able items: if the issue is not one of scope, I don't think there is any reason not to include it. It would make the engine more popular with players and modders.

One thing I have learned from releasing my own Diablo-like game is that players tend not to be happy if something that is expected in a certain genre of game is not there, despite my own personal vision as the dev for whether it 'fits' or not.

Of course, this is just my opinion so take it as you will, but the decision to allow for randomized stats on items definitely brings it closer to being seen as a 'proper' Diablo-like. Might open a can of worms however, some people want to use the engine to make games that are of different genres.

dorkster commented 1 year ago

Progress update

1871 is finished, but I need to test it more thoroughly to make sure there's no invalid memory accesses. But in it's current state, it was functional enough to start working on random item generation. I'm happy to say that it's all working pretty well. Let's take a look at my testing configuration:

items/items.txt

[item]
id=2003
name=Mysterious Cloth Shirt
INCLUDE items/base/armor/cloth/chest.txt
level=1
price=base:75,item_level:75
randomizer_def=items/random/test.txt

items/random/test.txt

[option]
chance=100
quality=high
bonus_count=1,1
level_src=base
level_range=1,1

[option]
chance=5
quality=epic
bonus_count=1,2
level_src=base
level_range=2,2

[option]
chance=0.5
quality=rare
bonus_count=2,2
level_src=base
level_range=3,3

[bonuses]
bonus=hp,item_level:1:25
bonus=mp,item_level:1:3
bonus=hp_regen,item_level:1:25
bonus=mp_regen,item_level:1:3
bonus=accuracy,base:0:5,item_level:1
bonus=avoidance,base:0:5,item_level:1
bonus=crit,base:0:5,item_level:1
bonus=absorb_max,base:0:5,item_level:1
bonus=poise,base:0:5,item_level:1
bonus=xp_gain,base:0:5,item_level:1
bonus=currency_find,base:0:5,item_level:1:2
bonus=item_find,base:0:5,item_level:5
bonus=fire_resist,base:8:10,item_level:1:2
bonus=ice_resist,base:8:10,item_level:1:2
bonus=lightning_resist,base:8:10,item_level:1:2
bonus=dark_resist,base:8:10,item_level:1:2
bonus_power_level=37,base:1
bonus_power_level=111,base:1
bonus_power_level=152,base:1

Generate/randomize

So how does it work? When item 2003 is dropped, we copy the item to a new ID above a certain threshold (currently hard-coded to 3000). The new item is what we'll call an "extended item". Once allocated, we pick an option that can set the item's quality, level, and number of bonuses.

The individual bonuses are rolled after that. It's important to note that the syntax for level-scaled values has been extended. Instead of a single value, there can now be 3 values, delimited by colons. All 3 together can define a range that the randomizer can use to pick a final value. The first value is the minimum and the second is the maximum. The third value is the "step", which defaults to 1. Say we want to generate a value between 1 and 5. We'd probably want the set of possible values to be (1, 2, 3, 4, 5) and not end up with something like 3.1459.

Storage

Random items get written to extended_items.txt under the game's save prefix. IDs will be consistent across save files from the same game, so shared stash usage is possible. Here's an example of the item from the screenshot shown below:

[item]
id=3014,2003
level=4
quality=rare
bonus_power_level=37,base:1
bonus=absorb_max,base:5,item_level:1

So we don't need to store everything about an item, the id property has both the generated ID as well as the ID of the item we need to inherit from. The nice thing about storing extended items like this is that it should be fairly simple to store other data, such as sockets/durability/identification/etc.

Image

dorkster commented 1 year ago

Implemented with https://github.com/flareteam/flare-engine/commit/7bb3ffb0cf179b4c8cf6c5954126b79c671ee43f