Improbable Island Message of the Day (MoTD)Scheduled downtime, Arbitrary Roleplaying Stats Engine
Staff 2020-09-25 17:56:12 [Permalink]
Hey, all - this coming Monday, 2020-09-28, we'll be going completely offline for a few hours around 17:00 UTC in order to set up a test server for our new stats system, and in the meantime all requests to the site will be redirected to our Fediverse presence at https://mastodon.social/@improbableisland, which will be used to communicate updates. If you wanna chat with me there you can set up a Mastodon account or use, well, pretty much anything in the Fediverse.
I guess I should probably talk a little about the new stats system I've been working on all month, huh!
It all started when we decided to multiply all the numbers by ten.
(having a rookie start with 10hp, 1atk and 1def limits what we can do to differentiate monsters and provide variety in the early levels. If they started instead with 100hp, 10atk and 10def, we could have some monsters have 6atk/14def, others have 12atk/8def, and so on. Also if a Spork gave +10atk and a butter knife gave +20atk rather than the +1 and +2 they do now, we could slot in a sharpened spork at +15atk. It opens things up in general for new ideas and more variety)
Anyway, I started off multiplying everything by ten. As the project continued it became increasingly clear that this wasn't going to be straightforward, as the game stores player stats in a destructive fashion.
Lemme give you an example. In the database table in question, there's a field called "attack" and a field called "weapondmg." If you're on your first DK, at level 10, with a screwdriver, you'll have 15 attack in total. One sensible way to record and retrieve this information using these two columns would be to have "attack" be 10 and "weapondmg" be five and then just add them together - but instead, the game stores "weapondmg" as 5 and "attack" as 15. Then, when you sell your weapon, it subtracts weapondmg from attack and then sets weapondmg to zero. When you do a Drive Kill, the game then subtracts your level and weapondmg from your attack points, then if you choose to add attack for your Drive Points it increments the attack points again.
Add Drive Points, Stonehenge, the Gauntlet and other modules that permanently affect stats, and it becomes rather tricky to figure out what your stats should be immediately after a DK. It's not readily apparent where your various points have come from, and there's lots of room for screwups - as I found when I wrote a test program to try to find out where people's stats have come from, and found that around 4% of players have weaker stats than they should, and around 0.5% of players have stronger stats than I could account for.
The analogy of this current system is an RPG character sheet where you pencil in your total attack, and then when you get new gear you rub out the old value, subtract your old gear, add your new gear and write in the new value. If you make a mistake at any point, then your math is gonna be wrong until you notice and then have to try to remind yourself where all these numbers came from.
The new system - which I was calling Arbitrary Stats System until I noticed that the acronym was inappropriate and changed it to Arbitrary Roleplaying Stats Engine - is more analogous to a stack of counters, each of which marked with its origin.
It works like this. There's a new database table, just for stat changes. When you buy your first weapon, we write a new row into the table. The new row explains the stat that we're changing, how much we're changing it by, and where the change came from (so it'll be something like ["attack",10,"weapon"]). Some weapons give both attack and a little bit of defence - in that case we add another row, saying for the sake of example that the weapon adds 2 defence we'd add a row saying ["defense",2,"weapon"]. When we want to know your attack power (say, in a fight), we just add up all the rows with the "attack" attribute. When you sell or lose your weapon, we just erase the rows that came from "weapon" - it works the same way when you level up, we add three rows (one saying ["attack",10,"level"], one saying ["defense",10,"level"], and one saying ["maxhitpoints",100,"level"]) and then when you DK, we just erase anything that came from "level".
This means that your stats are added up on-the-fly every time we need to know them (which sounds slow, but really isn't - if there's one thing computers can do quick it's add things up, and the actual database query is very fast indeed), which means there's far less chance of you ending up with unexplained or incorrect stats. Each stat modification serves as its own "receipt," and carries a timestamp from when your stat changed.
Banks work like this (at least, most of them these days). When you ask a bank for your current balance, that balance isn't actually stored anywhere - instead, behind the scenes, the bank starts a number at zero, then runs through every single transaction you've ever done in that account, all the adding up and taking away done in the blink of an eye, and spits out the number it ends up with. It does it this way so that if any given transaction is hinky, it can simply void that one transaction and your balance is automatically correct.
So, my Arbitrary Roleplaying Stats Engine is pretty reliable. Furthermore, it's flexible.
Previously, when you DK'd we would remove 15 points from attack, 15 from defence, and 150 from maxhitpoints. We're not doing that anymore, we're just erasing any table rows that came from "level", so we don't necessarily have to add the same amount to each stat for each level. We could even, once we've got Arbitrary Roleplaying Stats Engine established and warmed up and comfortable, start exploring its flexibility by doing things like giving you a certain number of points per level to allocate between attack, defence and maxhitpoints.
(I should stress at this point that Arbitrary Roleplaying Stats Engine is new and will take some breaking in and getting used to, so don't expect massive changes straight away - rather, as we get used to playing with Arbitrary Roleplaying Stats Engine and seeing if it reacts well, we can start to demand more of it. It's good to take these things slow and steady.)
Furthermore, Arbitrary Roleplaying Stats Engine is accomodating. Because we don't have columns for "attack", "defense" etc, just a column labelled "stat" that we can write anything in, we can in the near future bring in new stats without having to rewrite a bunch of code. Speed, dexterity, luck, steadyhandedness, all of this becomes possible because Arbitrary Roleplaying Stats Engine can handle pretty much anything you'd want to stuff into it.
Anyway, there's lots of possibilities in the near future for fighting with our Arbitrary Roleplaying Stats Engine. In the meantime, we'll be down for a few hours on Monday while I copy the current database to our new beta server, and on Tuesday I'll open the beta server and invite you all to descend upon my Arbitrary Roleplaying Stats Engine and really give it a damn good hammering to see if anything breaks.