Diablo 2 as an Inspiration - Managing Game Data Using CSV
A Love Letter to Diablo 2
I’ve always been fascinated by Diablo, but particularly so on the series’ loot system, and ESPECIALLY so in Diablo 2. Depending on your current goal (and character build), each enemy could be just fodder to be mowed down in your advance to the next quest location or is a potentially valuable tug on the slot machine handle. Or maybe both!
After participating in the 2022 Game Dev TV Game Jam, having had some very helpful feedback from my fellow participants (thank you!), I took stock, had a bit of a break and considered which direction to go in. I had an idea to do something reasonably unique, or at least something based on games that you’d need to be a bit of an ‘older gamer’ to have played at their time of release.
Amongst other thoughts on directions for the space shooter genre, such as ‘trading sim’ (Elite [1984]) and ‘Ultima-lite RPG’ (Space Rogue [1989]), or the frenetic PVP Asteroids style shooting action of Continuum (aka Subspace [1997]) I always had an idea of making a ‘Diablo in Space’. I don’t really feel this sub-genre has been covered or at least I can’t think of any games I’ve played in this realm.
Please feel free to correct me on this! I plan to work in some elements from Elite and Space Rogue, but the main gameplay will be a Diablo-style ARPG in a space shooter world.
Perhaps Galak-Z is the closest, with its procedurally generated levels and random loot. Though the itemisation is more ‘JRPG / J-shooter’ style, i.e., limited equipment modules (that have a big impact), rather than the broad scope of items, rarities, prefixes and suffixes you’ll find in Diablo, Path of Exile, etc. (that often have a smaller, more incremental effect on your progress).
In any case, I’m a one-man band, so I need to rein in my ambitions a bit and set scope appropriately. To that end, proc-gen levels are out, multiplayer also, (and never-mind those Hollywood-tier cutscenes) but I think everything else in Diablo 2 is fair game…
Managing Enemy and Item Data
So, back onto the blog’s theme. Something I’ve had bouncing round my head is how to manage data for enemies, loot, and space furniture (asteroids, etc). I am developing in Unity, so there’s the usual options of mixing and matching between Game Objects (and Prefabs), Scriptable Objects, and serialisation of plain old C# objects.
I expect to end up with a lot of different enemy types and items, which will need regular re-balancing. Frankly, navigating Unity inspectors to set values is not my idea of a good time, so this weekend I played around with implementing similar data structures as Diablo 2 (which are basically CSV files).
Diablo 2 Item Generation Deep Dive
As a bit of background, Diablo 2 uses several CSV files (tab delimited) which hold data on every monster, every weapon, every armour piece, cube recipe, loot tables (treasure classes), etc. etc. These can easily be opened in Excel and played around with – great for modding, and the D2 modding scene is still huge. These files can be thought of as a relational database, loosely linked via id (code) columns.
The monstats file contains a row for every monster in the game (705 rows!), though of course many of them are palette swaps of a base monster (e.g., zombie, skeleton). Each monster has an id, minHP, maxHP, and of particular interest for this blog post: several columns for TREASURE CLASS. For now, we’ll ignore champions and superuniques (they get special TCs), and just look at your common or garden (trash) monster.
For example, ‘fallen1’ – the first Fallen type monster you will encounter, has a level of 1, minHP: 10, maxHP: 18 and a treasure class: Act 1 H2H B. As an aside its internal name is ‘Orcling’, suggesting in early development these monsters were more Warcraft inspired…
So, what is Treasure Class Act 1 H2H B? Let’s look it up in the treasureclassex file:
So this treasure class can drop up to level 9 items, but as our Fallen is only a level 1 monster, drops are limited to level 1 (quite a small pool of items). Picks: can drop up to 1 item, then the chances of dropping an item are:
No Drop | 110 |
Gold | 19 |
Act 1 Equip B | 21 |
Act 1 Junk | 7 |
Act 1 Good | 2 |
Expressed in percentages, that results in:
About a 7/10 chance of no loot. Junk is potions, crossbow bolts. Gold is well, gold. Equip is armour and weapons. And there’s short odds on anything ‘good’. But what is in ‘Act 1 Good’..?
We get 50:50 on something from Jewelry A or the Chipped Gem TCs.
The Chipped Gem TC has a 15% chance for each chipped gem type and a 10% chance for a chipped skull…
Or if the RNG decides it’s giving out a Jewelry A, this is where a ring, amulet, jewel or charm will drop.
And these items then run into Diablo 2’s system for generating item rarity: magic, rare, set, unique, suffixes, affixes and all that goodness. The player's Magic Find comes into play here. All this is considerably more complicated that what I've described above, and ABSOLUTELY will need a blog post of its own :)
So, as you can see, the game runs through potentially a LOT of iterations just to figure out what that evil little red demon has decided to drop for you.
Time for some C# Code
So that was a nice little history lesson, but how can we implement this in Unity? In my case, I installed the excellent CSVHelper nuget package and had a play with the ‘monstats’ file.
Here’s some code I used to map the monstats.txt file into a class I called ‘AlienStats’. The Map class is used to map the CSV column headers by name to the AlienStats properties. At the moment I’m just mapping the monster (or alien in my case)’s name and health information (sorry for the pictures, itch doesn't seem to have a way to handle code blocks in a pretty way):
And below is the code to read the CSV file, put its data in a List and get a row of data based on an Id (code):
Reading it all into a List may be a bit inefficient, so I may change the code to look things up just in time (or cache anything looked up).
Summary
There is so much going on under the hood in Diablo 2’s item generation systems. It has always fascinated me in a way that no game really has since. I didn’t even touch on the effects the /players x command or playing in a party has (basically the nodrop percentage gets reduced). Or the special drop behaviour on bosses and non-trash mobs.
Next steps for my game would be to start mapping the treasure classes and items and working in a system to equip items. In my further development of Catacombs of Venice– my GDTV Jam entry for 2021 (currently paused) – I made use of the GDTV RPG course’s system, but it’s a little over-engineered for my liking so I’ll probably roll something simpler.
I hope this post was interesting, please let me know if you have any thoughts. I'm looking to setup some regular dev log updates and generally get feedback to keep the motivation levels up ;) Socials and a Discord to come..!
PS. This post's title image was a Blizzard Valentine from 2012.
Lost in the Stars
A fast-paced, yet relaxing 2D space shooter (GDTV '22 gamejam entry)
Status | Released |
Author | christh |
Genre | Action |
Tags | 2D, Pixel Art, Retro, Sci-fi, Shoot 'Em Up, Singleplayer |
Leave a comment
Log in with itch.io to leave a comment.