Around 15 years ago, when casual little games on Facebook were still a thing (actually when Facebook itself was still a thing), I used to play Yahtzee on the site while watching TV shows or whatever. It was one of the most popular games on there. For me it was something to fidget with (there was no money involved or anything, just a personal high score), so I played it a lot.
I felt more and more that dice values of specifically 1 and 6 were harder to come by than other values, so one day I sat down for a few minutes and logged the value of 100 or so dice throws. Turns out I was right, the distribution was not uniform: 2-5 were fine, but it seemed that it was twice as hard to get a 1 or a 6 compared to any other value.
I even did a chi-squared hypothesis test, because I was crazy. (And because I was studying for my statistics minor in university at the time).
Seeing the result, the problem was pretty clear, without even knowing the source code. Almost certainly, they had a random number generator giving a number in a uniform range, let's say from 0 to 1, and did something like the following to get a dice value from 1 to 6:
value = round(random()*5)+1
Do you spot the issue?
The problem is that round() rounds to the nearest integer. So any value between, say, 1.5 and 2.5 (exclusive at one end) rounds to 2, 2.5-3.5 rounds to 3, and so on. Add 1, and you have the dice value.
But the ranges for dice values 1 and 6, are only 0 to 0.5 and 4.5-5 respectively, so ranges that are only half the size.
The fix should be extremely simple:
value = floor(random()*6)+1
The crucial point being to use floor() or ceil() instead of round(), to only round towards one direction.
I wrote up exactly this in a short email to the company that made the Yahtzee game. They did not reply and just silently fixed the bug, right after my email. I was disappointed and stopped playing.
> I wrote up exactly this in a short email to the company that made the Yahtzee game. They did not reply and just silently fixed the bug, right after my email. I was disappointed and stopped playing.
I love this. It's one of those things that's entirely intelligible to me but I imagine would be next to impossible to explain to a Martian.
But here's another layer, though. What if it isn't?
Our science fiction is filled with this fairly human-chauvinistic worldview where even in a hypothetical future where we are rubbing shoulders with many different alien species, many of them technologically superior to ours, some of them still admire or begrudgingly respect us for our ingenuity, spirit, some je ne sais quoi.
That we're illogical and inconsistent and jealous and petty and insecure, but also humble and funny and empathetic and creative.
But...we have no evidence that this would be unique about humans whether sentient intelligence is common throughout the universe or rare. In fact, it's quite possible, that this is a necessary prerequisite, side effect, or consequence of conscious intelligence.
So this hypothetical martian maybe would just smile, nod and say "Ah yes, the company was embarrassed, or didn't want to risk liability, or didn't want to risk their reputation being compromised. But OP just wanted a thank you. He wouldn't have wanted money, just a 'hey thanks for finding that for us'. And it soured him on the whole experience. Been there, my new human bro, been there."
edit: I wrote this before I saw the rest of the replys, and HOLY, there's a bunch of humans that don't understand why OP stopped playing.
> the distribution was not uniform: 2-5 were fine, but it seemed that it was twice as hard to get a 1 or a 6 compared to any other value.
As soon as I saw that, I knew exactly what the problem was. I'm glad I was reading on a small mobile screen, so I didn't feel like I was cheating by getting a hint from the rest of your comment.
Yes, voice of painful experience here!
> The crucial point being to use floor() or ceil() instead of round(), to only round towards one direction. [emphasis added]
Not quite. If the random() function in your language returns a value in a half-open interval like Math.random() in JavaScript or random.random() in Python, only use floor(), never ceil().
Those random() functions return a value n where 0 <= n < 1. In other words, n may be 0 but will never be 1. So floor() is always what you want for a random function like that.
A somewhat related tip for anyone who implements a progress message like "nn% done". You should always use floor() for that number as well. Quite often I see a case where someone has used round() instead, or possibly ceil(). And then what happens is your notification message says "100% done" when the process is not 100% done. It makes me a little crazy when I see that. Use floor() and you won't have this problem.
Yep, you're right, including ceil() was misleading of me, if not downright wrong. I technically did not specify which side the interval is open on. But practically and realistically, in pretty much any scenario it will be a half-open interval that excludes the upper bound, and you have to go out of your way to get it the other way around (at which point you probably well know yourself to use ceil() instead of floor()).
> Quite often I see a case where someone has used round() instead, or possibly ceil(). And then what happens is your notification message says "100% done" when the process is not 100% done.
The video game Destiny has this problem with how it displays objective percentages - it will round up, and there's a quest every now and then that shows progress as a percentage and has a high enough denominator to trigger this.
Heh, I remember running into something similar professionally, using the .NET Framework to generate random numbers: When asked to generate random integers, it has a seemingly innocent conversion from integers to floating points and back that ends up causing significant bias on large ranges. Specifically, `Random.Next(b)` produces an integer between 0 and b − 1 by
1. taking a random integer between 0 and 2^31 − 2,
2. dividing the integer by 2^31 − 1 to get a double-precision floating-point between 0 and 1,
3. multiplying this floating-point with b to get a number between 0 and b,
4. taking the integer part of this new number to get an integer between 0 and b − 1.
Do this for b = 2^31 − 1, and 50.34% of outputs are odd numbers, where you'd expect (almost) as many evens as odds.
Another fun thing about their RNG was that it was apparently supposed to follow Knuth's provably useful additive PRNG which, given n − 1 randomly generated numbers, generates a new number by taking the sum of the (n − 24)'th and (n − 55)'th numbers modulo some specific number; back when I looked, Microsoft's implementation for some reason uses 34 instead of 24, probably just a typo, with the unfortunate side effect that Knuth's theoretical guarantees are out of the window.
Interestingly that Yahtzee version was rigged in the player's favor since they're more likely to get X-of-a-kind if the same numbers appear more often. Average scores probably dropped a decent bit after that fix.
For the short time that I knew about it and it was not fixed yet, I integrated it into my strategy. 1 and 6 are rare, so if for example I still needed them for something, I was inclined to make good use of 1 and 6 when they came up, instead of rerolling them for something else.
After I (happily!) did their work for them, a simple "thank you", or even an acknowledgment through a closed ticket, would have entirely sufficed to make my day.
I sent a patch to a bigger and more known software company, now defunct. I ended up writing some rude comments in the bug submitting form, after being forced to enter endless data about me, the company that I worked for and a lot of information about how to reproduce the error. Not proud of it, but I understand the GP: you're helping them and they treat you poorly.
They included the fix in the next version of the tool. I later noticed it was incomplete, but this time I just made the correction locally.
I remember writing a suggestion letter to Maxis about SimCity and they not only replied but also sent me a copy of the Terrain Editor. Very nice of them.
I had the impression 1 and 6 weren’t as rare anymore (even a single game is a lot of dice throws, and I usually played several in a row and restarted a lot), so I sampled again. No chi-squared test this time, that was just for my learning, because it was obvious without.
Really didn't expect to see AC at the top of HN. Asheron's Call was the first game I worked on and I remember all the times we'd joke with Wi about it and watch monsters beeline for him. It seemed like one of those "Haha sure, player perception" problems and not something that was actually real. IIRC someone did a very cursory look at the code at one point but it never bubbled up as important enough to assign someone to to actually investigate.
Wi came to one of the player gatherings with little printed out cards and would hand them to people and say, "You've been Wi flagged!"
I loved Asheron's Call, played it a lot back in the day. My friends and I were in high school at the time so we had absolutely no idea what we were doing, but that didn't stop us from running around the world goofing off. My hobby was making characters with totally insane Run and Jump skills. Once you leveled up enough you could literally leap from one end of a town to the other like Superman, it was extremely funny. The character was awful in all other regards, but I didn't care. I made another character whose sole purpose was to climb to the top of the highest cliff or building I could find, and jump off it. And there were some HIGH places in AC. I miss being able to play MMO's innocently like that rather than trying to min-max every last bit of efficiency out of everything, as embodied by WoW (another game I loved, but for different reasons).
I also really enjoyed the periodic story events that had really dramatic impacts on the world, like the shadow invasion. It was a great game, especially for its time. So thanks for whatever part you played in its creation.
Thanks! Always nice to hear people who "grew up" play it. AC having server-side physics and actually making use of them led to lots of ridiculous and emergent gameplay. I don't know how many hours I just spend idling in towns jumping from rooftop to rooftop or seeing how high I could climb up massive structures. Everytime I try to play again though, the old "you can't go home again" hits too hard and I just quietly close it back up and go back to the nostalgia.
I was on the design team, so was directly responsible for a lot of the shadow invasion stuff (if you ever saw the big bad Bael'Zharon running around in the live events, that was me!) and other patches for the first 2 years of its lifespan.
Weirdly, I work on WoW now with my career having come full circle after having not worked on MMOs since the mid 2000s. :)
AC is one of my favorite games of all time (neck and neck with Ultima II (I'm old)). I still play on the emulators from time to time - endlessly searching for more Hoary Mattekars.
I played on Thistledown and ran a little portal bot named Stip Dickens an Ayan Baqur that helped ferry people into the Shard of the Herald event. That was a lot of fun.
The loot system was also one-of-a-kind. I don't see that level of randomness in many other games.
The game felt like the writers and staff were highly literate and well read. I now know so many real life herbs and plants due to their use in spellcasting. And AC taught me words like "Mnemosyne".
And each month we would get several pages of amazing lore. (Side note, there's an ongoing web serial called "The Wandering Inn" that reminds me quite a bit of AC. People dropped into a video game like world, insect people, references to a "Zeikhal"(similar to a town name)....
So, I just want to thank you for your work on AC. It's had a profoundly positive impact on my life.
You're welcome! Haha, mattekar farming will always hold a special place for me. And, of course, TD's herald defense is probably top 3 gaming memories for me. So much lifting done across the community for what's now basically oral history.
But also thank YOU for participating in some of my very formative experiences of my life as well. The players really made it a joy to work on.
I was in from beta until about 2004. Lots of fond memories! Closest I've come to feeling the same way I felt playing AC in recent memory is actually Valheim. Can't quite put a finger on why, but there are very few games that hold such an important place in my heart. I was a high schooler when it came out. Some days I regret not going into game design, especially with the current wave of VR games. Some days I'm tempted to quit my major tech company job and try to create that magic myself in a VR MMO.
But that would be something only a crazy person would do.
Yay! The first time an MMO lands for someone, it definitely makes an outsized impression. The combination of social outlet with a huge amount of free time is a recipe for something great.
It's funny you mention Valheim - one of my groups in had a core of people who I met back in the AC days and their friends. We got to some real old man gaming that probably annoyed their friends with all of the "back in our day..." stories while we were running around the landscape, running from trolls, etc.
Add me as another with fond memories. I was introduced to AC by my coworkers at my first full time job after college. Pretty much all the software devs I worked with at the time played it, including both my manager and the head of the site. Our office had our own little monarchy on Leafcull at first, though we later joined up with a bigger group.
On patch day, the office banter usually centered around the things we were seeing popping up as we'd reload Maggie the Jackcat's community-sourced patch notes throughout the day [0].
Sometimes we'd even download the patch and log in for a few minutes, just to poke around. (Always being careful not to do anything _real_ due to the risks the infamous patch day server rollbacks.) Then there'd the be waiting for the Decal updates.
I still remember that my main was a tank archer build, which was pretty much untouchable going toe to toe with the mobs in PvE as long as the stamina held out. I went through a _lot_ of stam potions, though!
I remember also finding somewhere about how to extract the terrain data from the game. I scraped the coordinates for various destinations from some place and wrote a little OpenGL viewer that would let me do flyovers with the various locations marked with labelled bullets.
AC was my first MMORPG, fond memories indeed. I remember the sheer adrenaline I got when "going red" and watching PK drama and battles unfold at the subway, dominated by a build called the "OG mage," slidecasting all over the place casting drain health until finishing with a missile spell. I would cast Blooddrinker 6 on monster weapons and giddily laugh as they sliced through new players starting out. I remember staying up the entire night during a school day when housing was released and being one of the first people on my server to claim one. I even remember being a vassal to a very generous asian guy in his mid twenties living in LA named Kyoto and my countless interactions with him and his brother under a specific tree.
Countless memories I could keep going on and on, but what an experience!
Haha "Og mage" ... yeah. The combat of AC still holds up in its janky for being fun in the context of an MMO. I spent most of my playtime on Darktide and dear lord, it made me so sweaty.
It's amazing to me how many people are still friends with their patrons/vassals from 25 years ago.
A fellow comp sci major in college introduced me to AC. Bought it on a whim after seeing him play it in his dorm. I still remember the physical box with some special bonus map and swag.
Lost so much sleep power levelling on a rock with those ape like creatures and just spamming magic to discover new combinations. The discovery and wonder does not match up with the graphics I see now when I search for screenshots and videos. Beta and early WoW almost had the same effect but your first is always special.
Min-max:ed dagger warrior for the win! Also, fear the ash gromnie! AC was never really trumped for me (AC2 was... different?). I just wanted a world to roam, and the vassal system is probably the only pyramid scheme that incentivised making social connections. :) My patron did a lot corpse runs for me.
For the last 15 years or so, coworkers ask when I'm going to make a new allegiance system but "less broken". So many good social behaviors came from its structure that it really deserves another attempt.
And yeah, Ash Gromnies were the bane of so so so many players.
In retrospect, I give a lot of credit to the fact that we were young and dumb and didn't know any better. I've been revisiting a lot of the stories from back then and so many of them end up with us saying, "I dunno, let's see what happens!" and not being dissuaded by "best practices" or even common sense.
Also lots of credit goes to the early internet era when people were a LOT more forgiving of, well, everything.
I had been gone from Turbine for 8 or 10 years by the time they decided to shut AC down, so I can only speculate. I assume it had something to do with WB not wanting to "give away" the IP but instead just lock it away in a vault.
I've seen a similar mistake in a rushed "feature flagging"/phased rollout system.
User IDs were random UUIDs. Let's say we want to release a feature to ~33% of users; we take the first 2 characters of the UUID, giving us 256 possible buckets, then say that everyone in the first 1/3 of that range gets the feature. So, 00XXX...-55XXX... IDs get it, and 56-FF do not. This works fine.
However, if we then release another feature to 10% of users - everyone from 00-1A gets it, 1B-FF do not. That first set now has both features, and 56-FF have none. It turns out you can't draw meaningful conclusions when some users get every new feature and some get none at all.
One easy way to avoid this problem is to give each feature its own independent space of “dice rolls” by hashing the user ids with feature-specific constants before interpreting them as dice rolls:
If you suspect some flag effects interact with each other (e.g. one flag increases button size by 10%, and the other decreases it by 10%) you can go one step further and define feature groups and hash by user-id + group-id and then assign non overlapping ranges to the flags.
A better way is to assign some internal salt to the feature at creation time and use that, that way you are not dependent on something external that user (the creator of the feature flag) could change.
I bear the scars of this design mistake from when I worked for a company that provided feature flagging.
It was not my initial mistake, but I drew the short straw trying to work around it.
Is there a more general term for tuple hashing? IE, math and theory around composition of hashes composed of concatenated (or otherwise combined) typed values?
> That first set now has both features, and 56-FF have none. It turns out you can't draw meaningful conclusions when some users get every new feature and some get none at all.
00—1A: have feature flags A and B
1B-55: have feature flag A only
56-FF: have no feature flag
So the actual gotcha here is that there is no cohort for "feature flag B only", right?
This setup can actually be desirable if feature B depends on feature A.
> So the actual gotcha here is that there is no cohort for "feature flag B only", right?
And that, as you add more tests, user 00 will always get the test treatment for every test. If you're running a lot of tests which introduce experimental features or changes to workflows, user 00 is probably going to find the site a lot more chaotic and hard to understand than user FF, and that will skew your test results.
> So the actual gotcha here is that there is no cohort for "feature flag B only", right?
Yep, exactly - by "that first set" I meant the 00-1A group, could have been clearer. Whatever the smallest rollout bucket is, that group is guaranteed to have every single feature.
This was quite a while ago, but I think the actual case we noticed this with was several features released to 50% of the userbase - so every single user either had all or none at once (unintentionally)
Sandra Powers (who finally figured the problem out) and her husband have been writing and running their own MMO for quite a while now. Check out http://projectgorgon.com/ if you’re interested in something handcrafted, quirky, and high quality.
I had the pleasure of working with Sandra at SOE for a while on EverQuest II, and later I contracted with her and Eric to help at my startup Ohai. They are both wonderful people and it's great to see this game is still ongoing.
My favourite part of this story is that Sandra's handle on the fansites at the time was "srand". A highly appropriate coincidence, given the nature of the bug!
One of my favorite things in gaming is when lore develops from bugs.
When they added the ability for Kerbals to be killed in Kerbal Space Program, they tripped over a bug where the first Kerbal in the game's engine, Jebediah (the one who dated back to the original introduction of astronauts at all, where only one existed), could not be killed. Because of some of the game logic having gone unmodified from the earlier versions, some operations would cause him to be loaded into the pilot seat and those operations didn't check if he was deceased. As a result, you could lose him on a mission only for him to spontaneously appear at the controls of another mission.
The community responded with fan-art of "Jebediah Kerman, thrillmaster."
My theory for why people think they are being "shadowbanned" or otherwise targeted by a social media company is often because of bugs like this. They are weird and almost like gaslighting in the way you experience them and people who don't understand how these bugs can exist assume sinister motives.
I remember Facebook around ~2010 would often seemingly delete posts I published, or hide them from some of my friends. Or from me. I could easily confirm that by viewing my profile from another browser that wasn't logged in, or having a friend sitting next to me open my profile.
Of course, it wasn't any kind of UI bug or automated moderation. The experience gave me a visceral understanding of what eventual consistency means - a term I also first learned around that time, during internship in an Erlang company, and connected the dots.
I was one of the first people in my social circle to spot the issue, but as it became apparent over a year or two before eventually getting fixed (or at least made less obvious), I ended up giving a very high level intro to distributed databases to quite a few non-tech people, in order to alleviate their concerns about Facebook gremlins.
This and other experiences using and building software systems make me agree with you. Especially for large web platforms, that weird thing you're experiencing could be some nasty form of shadow ban, but if you just noticed it after doing something, then chances are it's just a transient issue with queues or database consistency.
Shadowbanning is a very real phenomenon; my current Reddit account was shadowbanned twice because I had created and posted memes which got unusually high upvotes for a new account, and the algorithm thought I was a bot reposting images to farm karma for future spamming. And from time to time I see HN users whose posts are flagged by default. I'm less sure if/how shadowbanning occurs on Twitter.
It reminds me of the "charm tables" of some Monster Hunter games. Charms are equipment with randomly selected skills. When you create a character, you are assigned a random "table" and all charms you may get are selected from that table. There are 17 of them, 12 of them are normal with some slightly better suited to some play styles but it is a really minor thing, the remaining 5 are called "cursed tables", they are much smaller and you will never be able to get the best charms. It is not game breaking, but it is annoying if you want a highly optimized build.
The reason it happen is that the random number generator has only a small state (I think 16 bits) a limited number of possible rolls, and some seeds have a really short period, which limits it even more. Also, the seed is stored in your save file. It means that if you have a bad seed, you will always have a seriously broken RNG and the only way to change that is to create a new character. I think in later games, the same terrible RNG is used, but a new seed is picked each time you start the game, so you won't stay in the same "table". And while "charm tables" are the most obvious consequence, if probably has other, less noticeable effects on gameplay.
The weird part is that while it is obviously a bug as it negatively affects the experience of some random players, it is rarely referred to as such. It even persisted between versions. Some people even wrote tools to find out early on which table you are, and techniques to get the table you want, along with a variety of RNG manipulation exploits.
Some of my fondest gaming memories are from this game. There was nothing ever quite like it, and the allegiance system created a special type of community bond that I haven’t seen repeated.
At one point I had 10 “vassals” sworn to me, and in our allegiance that came with the expectation that you assist and mentor those under you. Stakes were higher when our allegiance committed to being red dot PKs on a white server with a few other stronger groups in play.
The server emulation scene has come a long way since retail shut down, but even the most populous servers are a pale shade of this game in its hey day.
MMOs are just so expensive to develop now that innovation is almost dead. You either make a WoW-like or you die (and many times you die anyway). They really don’t make MMOs like they used to.
Social media has taken a significant bite out of what I would consider the more important parts of the older MMOs, especially when it comes to apps like Discord. Not enough people want to interact in games anymore outside of specific gameplay scenarios.
That's because AC started development before even Ultima Online launched. It was started by a bunch of college students that loved MUDs and had no idea what they were actually doing.
It was such a special thing before it was hit with a lot of road grading over the 15+ years of monthly patching that smoothed a lot of the rough edges that made it really unique.
> MMOs are just so expensive to develop now that innovation is almost dead.
I look at this differently. I think the extreme cost of an MMO should force innovation. Take the constraints for what they are and run with them. Accepting that you can't do it the "traditional" way is the first step to figuring out a better way.
There is nothing that says a high-quality WoW killer absolutely must cost 10 figures to produce.
Basic probability - randomly walking a graph will tend to have you in regions of higher vertex density. Same reason why randomly picking a road intersection will tend to put you in cities - cities just have most of the intersections.
(the walk isn't exactly random but it still works - the pathing heuristic is real-coordinate agnostic).
I felt more and more that dice values of specifically 1 and 6 were harder to come by than other values, so one day I sat down for a few minutes and logged the value of 100 or so dice throws. Turns out I was right, the distribution was not uniform: 2-5 were fine, but it seemed that it was twice as hard to get a 1 or a 6 compared to any other value.
I even did a chi-squared hypothesis test, because I was crazy. (And because I was studying for my statistics minor in university at the time).
Seeing the result, the problem was pretty clear, without even knowing the source code. Almost certainly, they had a random number generator giving a number in a uniform range, let's say from 0 to 1, and did something like the following to get a dice value from 1 to 6:
Do you spot the issue?The problem is that round() rounds to the nearest integer. So any value between, say, 1.5 and 2.5 (exclusive at one end) rounds to 2, 2.5-3.5 rounds to 3, and so on. Add 1, and you have the dice value.
But the ranges for dice values 1 and 6, are only 0 to 0.5 and 4.5-5 respectively, so ranges that are only half the size.
The fix should be extremely simple:
The crucial point being to use floor() or ceil() instead of round(), to only round towards one direction.I wrote up exactly this in a short email to the company that made the Yahtzee game. They did not reply and just silently fixed the bug, right after my email. I was disappointed and stopped playing.
I love this. It's one of those things that's entirely intelligible to me but I imagine would be next to impossible to explain to a Martian.
But here's another layer, though. What if it isn't?
Our science fiction is filled with this fairly human-chauvinistic worldview where even in a hypothetical future where we are rubbing shoulders with many different alien species, many of them technologically superior to ours, some of them still admire or begrudgingly respect us for our ingenuity, spirit, some je ne sais quoi.
That we're illogical and inconsistent and jealous and petty and insecure, but also humble and funny and empathetic and creative.
But...we have no evidence that this would be unique about humans whether sentient intelligence is common throughout the universe or rare. In fact, it's quite possible, that this is a necessary prerequisite, side effect, or consequence of conscious intelligence.
So this hypothetical martian maybe would just smile, nod and say "Ah yes, the company was embarrassed, or didn't want to risk liability, or didn't want to risk their reputation being compromised. But OP just wanted a thank you. He wouldn't have wanted money, just a 'hey thanks for finding that for us'. And it soured him on the whole experience. Been there, my new human bro, been there."
edit: I wrote this before I saw the rest of the replys, and HOLY, there's a bunch of humans that don't understand why OP stopped playing.
As soon as I saw that, I knew exactly what the problem was. I'm glad I was reading on a small mobile screen, so I didn't feel like I was cheating by getting a hint from the rest of your comment.
Yes, voice of painful experience here!
> The crucial point being to use floor() or ceil() instead of round(), to only round towards one direction. [emphasis added]
Not quite. If the random() function in your language returns a value in a half-open interval like Math.random() in JavaScript or random.random() in Python, only use floor(), never ceil().
Those random() functions return a value n where 0 <= n < 1. In other words, n may be 0 but will never be 1. So floor() is always what you want for a random function like that.
A somewhat related tip for anyone who implements a progress message like "nn% done". You should always use floor() for that number as well. Quite often I see a case where someone has used round() instead, or possibly ceil(). And then what happens is your notification message says "100% done" when the process is not 100% done. It makes me a little crazy when I see that. Use floor() and you won't have this problem.
The video game Destiny has this problem with how it displays objective percentages - it will round up, and there's a quest every now and then that shows progress as a percentage and has a high enough denominator to trigger this.
1. taking a random integer between 0 and 2^31 − 2,
2. dividing the integer by 2^31 − 1 to get a double-precision floating-point between 0 and 1,
3. multiplying this floating-point with b to get a number between 0 and b,
4. taking the integer part of this new number to get an integer between 0 and b − 1.
Do this for b = 2^31 − 1, and 50.34% of outputs are odd numbers, where you'd expect (almost) as many evens as odds.
Ended up doing a bit of a write-up here: https://fuglede.dk/en/blog/bias-in-net-rng/
Another fun thing about their RNG was that it was apparently supposed to follow Knuth's provably useful additive PRNG which, given n − 1 randomly generated numbers, generates a new number by taking the sum of the (n − 24)'th and (n − 55)'th numbers modulo some specific number; back when I looked, Microsoft's implementation for some reason uses 34 instead of 24, probably just a typo, with the unfortunate side effect that Knuth's theoretical guarantees are out of the window.
They included the fix in the next version of the tool. I later noticed it was incomplete, but this time I just made the correction locally.
Deleted Comment
Deleted Comment
Wi came to one of the player gatherings with little printed out cards and would hand them to people and say, "You've been Wi flagged!"
The fondest of memories.
I also really enjoyed the periodic story events that had really dramatic impacts on the world, like the shadow invasion. It was a great game, especially for its time. So thanks for whatever part you played in its creation.
I was on the design team, so was directly responsible for a lot of the shadow invasion stuff (if you ever saw the big bad Bael'Zharon running around in the live events, that was me!) and other patches for the first 2 years of its lifespan.
Weirdly, I work on WoW now with my career having come full circle after having not worked on MMOs since the mid 2000s. :)
AC is one of my favorite games of all time (neck and neck with Ultima II (I'm old)). I still play on the emulators from time to time - endlessly searching for more Hoary Mattekars.
I played on Thistledown and ran a little portal bot named Stip Dickens an Ayan Baqur that helped ferry people into the Shard of the Herald event. That was a lot of fun.
The loot system was also one-of-a-kind. I don't see that level of randomness in many other games.
The game felt like the writers and staff were highly literate and well read. I now know so many real life herbs and plants due to their use in spellcasting. And AC taught me words like "Mnemosyne".
And each month we would get several pages of amazing lore. (Side note, there's an ongoing web serial called "The Wandering Inn" that reminds me quite a bit of AC. People dropped into a video game like world, insect people, references to a "Zeikhal"(similar to a town name)....
So, I just want to thank you for your work on AC. It's had a profoundly positive impact on my life.
But also thank YOU for participating in some of my very formative experiences of my life as well. The players really made it a joy to work on.
But that would be something only a crazy person would do.
It's funny you mention Valheim - one of my groups in had a core of people who I met back in the AC days and their friends. We got to some real old man gaming that probably annoyed their friends with all of the "back in our day..." stories while we were running around the landscape, running from trolls, etc.
On patch day, the office banter usually centered around the things we were seeing popping up as we'd reload Maggie the Jackcat's community-sourced patch notes throughout the day [0].
Sometimes we'd even download the patch and log in for a few minutes, just to poke around. (Always being careful not to do anything _real_ due to the risks the infamous patch day server rollbacks.) Then there'd the be waiting for the Decal updates.
I still remember that my main was a tank archer build, which was pretty much untouchable going toe to toe with the mobs in PvE as long as the stamina held out. I went through a _lot_ of stam potions, though!
I remember also finding somewhere about how to extract the terrain data from the game. I scraped the coordinates for various destinations from some place and wrote a little OpenGL viewer that would let me do flyovers with the various locations marked with labelled bullets.
Good times!
P.S.: Anyone remember the Drudge Dance [1]?
[0] http://www.thejackcat.com/AC/Culture/Dereth/Dereth.htm
[1] https://www.angelfire.com/rpg2/dragons/Drudge_Dance.wav (direct link doesn't work; copy and paste URL instead)
Countless memories I could keep going on and on, but what an experience!
It's amazing to me how many people are still friends with their patrons/vassals from 25 years ago.
Lost so much sleep power levelling on a rock with those ape like creatures and just spamming magic to discover new combinations. The discovery and wonder does not match up with the graphics I see now when I search for screenshots and videos. Beta and early WoW almost had the same effect but your first is always special.
And yeah, Ash Gromnies were the bane of so so so many players.
I remember people theorizing it was due to a short name (only 2 characters), and so would create longer usernames to try and avoid the "curse"
In retrospect, I give a lot of credit to the fact that we were young and dumb and didn't know any better. I've been revisiting a lot of the stories from back then and so many of them end up with us saying, "I dunno, let's see what happens!" and not being dissuaded by "best practices" or even common sense.
Also lots of credit goes to the early internet era when people were a LOT more forgiving of, well, everything.
Any idea how the targeting algorithm was chosen? It does not behave the way this letter says that it should.
User IDs were random UUIDs. Let's say we want to release a feature to ~33% of users; we take the first 2 characters of the UUID, giving us 256 possible buckets, then say that everyone in the first 1/3 of that range gets the feature. So, 00XXX...-55XXX... IDs get it, and 56-FF do not. This works fine.
However, if we then release another feature to 10% of users - everyone from 00-1A gets it, 1B-FF do not. That first set now has both features, and 56-FF have none. It turns out you can't draw meaningful conclusions when some users get every new feature and some get none at all.
those poor cursed users. reminiscent of a joke that used to grace Paul Mineiro's blog (machinedlearnings.com) a few years ago:
> An old curse says: "may you always be assigned to a test bucket."
00—1A: have feature flags A and B
1B-55: have feature flag A only
56-FF: have no feature flag
So the actual gotcha here is that there is no cohort for "feature flag B only", right?
This setup can actually be desirable if feature B depends on feature A.
And that, as you add more tests, user 00 will always get the test treatment for every test. If you're running a lot of tests which introduce experimental features or changes to workflows, user 00 is probably going to find the site a lot more chaotic and hard to understand than user FF, and that will skew your test results.
Yep, exactly - by "that first set" I meant the 00-1A group, could have been clearer. Whatever the smallest rollout bucket is, that group is guaranteed to have every single feature.
This was quite a while ago, but I think the actual case we noticed this with was several features released to 50% of the userbase - so every single user either had all or none at once (unintentionally)
Deleted Comment
Also reminded me that I backed Camelot Unchained that's still kicking around in development after all these years.
Players claiming to be cursed, and the curse was real!
A very different sort of event that it reminds me of is the old World of Warcraft plague: https://en.wikipedia.org/wiki/Corrupted_Blood_incident
When they added the ability for Kerbals to be killed in Kerbal Space Program, they tripped over a bug where the first Kerbal in the game's engine, Jebediah (the one who dated back to the original introduction of astronauts at all, where only one existed), could not be killed. Because of some of the game logic having gone unmodified from the earlier versions, some operations would cause him to be loaded into the pilot seat and those operations didn't check if he was deceased. As a result, you could lose him on a mission only for him to spontaneously appear at the controls of another mission.
The community responded with fan-art of "Jebediah Kerman, thrillmaster."
Of course, it wasn't any kind of UI bug or automated moderation. The experience gave me a visceral understanding of what eventual consistency means - a term I also first learned around that time, during internship in an Erlang company, and connected the dots.
I was one of the first people in my social circle to spot the issue, but as it became apparent over a year or two before eventually getting fixed (or at least made less obvious), I ended up giving a very high level intro to distributed databases to quite a few non-tech people, in order to alleviate their concerns about Facebook gremlins.
This and other experiences using and building software systems make me agree with you. Especially for large web platforms, that weird thing you're experiencing could be some nasty form of shadow ban, but if you just noticed it after doing something, then chances are it's just a transient issue with queues or database consistency.
The reason it happen is that the random number generator has only a small state (I think 16 bits) a limited number of possible rolls, and some seeds have a really short period, which limits it even more. Also, the seed is stored in your save file. It means that if you have a bad seed, you will always have a seriously broken RNG and the only way to change that is to create a new character. I think in later games, the same terrible RNG is used, but a new seed is picked each time you start the game, so you won't stay in the same "table". And while "charm tables" are the most obvious consequence, if probably has other, less noticeable effects on gameplay.
The weird part is that while it is obviously a bug as it negatively affects the experience of some random players, it is rarely referred to as such. It even persisted between versions. Some people even wrote tools to find out early on which table you are, and techniques to get the table you want, along with a variety of RNG manipulation exploits.
At one point I had 10 “vassals” sworn to me, and in our allegiance that came with the expectation that you assist and mentor those under you. Stakes were higher when our allegiance committed to being red dot PKs on a white server with a few other stronger groups in play.
The server emulation scene has come a long way since retail shut down, but even the most populous servers are a pale shade of this game in its hey day.
It was such a special thing before it was hit with a lot of road grading over the 15+ years of monthly patching that smoothed a lot of the rough edges that made it really unique.
I look at this differently. I think the extreme cost of an MMO should force innovation. Take the constraints for what they are and run with them. Accepting that you can't do it the "traditional" way is the first step to figuring out a better way.
There is nothing that says a high-quality WoW killer absolutely must cost 10 figures to produce.
(the walk isn't exactly random but it still works - the pathing heuristic is real-coordinate agnostic).