Christchurch and boiling the ocean

By now, everyone is familiar with the events that happened in Christchurch, New Zealand. Long story short: someone went on a shooting spree in a mosque and streamed the entire thing on-line. There’s been responses all around, ranging from shitty ones (blaming the muslims) to more wholesome ones, where people showed great amount of supports for the victims.

This post is not about the shooting itself, though. It’s about technology, and technological illiteracy of certain actors.

Nearly as soon as the news broke, Facebook wowed to do their best to keep the video of the shooting off their platform. Google too did their best effort to remove the offending video from Youtube. However, that wasn’t enough for some companies who, believing that Google and Facebook haven’t done enough, decided to pull their ads. No moderation approach Facebook and Google have was blamed a lot for the situation. “What are you doing to ensure this doesn’t happen again?” Facebook and Google are being asked, with some proposing that Google and Facebook should moderate what people stream. CEO of one of the companies pulling the ads even went ahead to state the following:

“If the site owners can target consumers with advertising in microseconds, why can’t the same technology be applied to prevent this kind of content being streamed live?”

There’s only one problem with that.

Hot dog (determining what ad to serve is easy)

Computers have been a standard office equipment for over twenty years, yet for some reason people are still painfully unaware about how they work. Hearing things like “oh computers can do this, this means they should be able to do that as well” and “you made computer do this, therefore you can make computer do that” gets criminally common when you’re hanging around an average person (or the half of human population that’s dumber than that).

The fact is that ‘targeting consumers within microseconds’ is easy. When determining what ad to show, you don’t have to do much work. You’ve got end user’s profile, and you track them wherever they go. Did they search for ‘Steam’ and click the first link? Make a mark in the ‘likes video games’ box. Did they watch some game-related videos on youtube? That’s few more marks in the ‘likes video games’ box. Searching for arduino and/or other microcontrollers that you could use as a simple F-13 emitting keyboard? Put few marks in ‘tech enthusiast’ box. Did they search for [insert video game title] flac soundtrack torrent download? That’s one mark for the ‘likes video games’ box, one mark for the ‘audio enthusiast’ box, and one mark for the ‘probably needs VPN’ box.

When advertiser gets asked for an ad to show for this hypothetical user, they take a look at said boxes. “Hmm, that’s a lot of marks in the ‘likes video games’ box,” thinks the advertiser and serves user an ad for the game that’s getting released in the next few weeks. “But wait, this user needs to see another ad!” says the website. Advertiser looks at said boxes again, sees a lot of interest in the video game box but remembers it already showed the ad for Apex within last 30 seconds and decides against showing it. Next category on the list is ‘tech enthusiast’, so it decides to serve ad for USB type C connector (and I shit you not, that thing I got on reddit a few days back was indeed an advertisement for bags of USB type C connectors that you could solder on a PCB).

As you can see, simple stuff — you have a list of categories both for user as well as every ad, and compare them every time — and it’s really not a lot of work. Which is exactly why advertisers can serve you ads in milliseconds.

Not hot dog (determining the content of the picture is hard)

Taken from xkcd

In the last few years, we’ve seen vast improvements in recognizing what’s inside the image. Smartphones have AI-powered cameras that can somewhat accurately determine what they’re looking at. And by ‘somewhat inaccurate’ I mean hit or miss. On one hand, we do have facial recognition software, but that’s very specialized and useless outside its very narrow function. ContentID and similar systems can also work fairly accurately and quickly, as it’s comparing content of the video or a stream against a database of known sounds and videos — but if you show ContentId something that it hasn’t seen before, you’re not getting a hit.

Then you have more general attempts at object recognition, where accuracy is incredibly low. Most of the time, it will be able to tell a cat from a person. Sometimes it will even distinguish between a dog and a cat, but that’s where it ends. It won’t distinguish things where differences can be relatively small, such as distinguishing dragons from wyverns (dragons have 4 legs, wyverns have 2). It also won’t distinguish things where differences are inexistent: it won’t distinguish glass of juice from a glass of tea (often enough, the only difference between the two is the temperature as certain kinds of juice have a color that’s the same as the color of various types of tea). It won’t be able to distinguish lakes or even big rivers from a sea (unless you’re there and it takes a look at GPS and compass data).

In the same vein, it’s currently borderline impossible to reliably distinguish between a movie or a TV series, gameplay of a first person shooter game, any airsoft or paintball video, a police bodycam and an active terrorist shooting — a situation that, for all intents and purposes, happens approximately never.

That’s not all, though. Let’s pretend for a moment that there will be a point where AI can distinguish whether the live stream is an active shooting or not. Remember how I explained how finding the right ad for a visitor of the webpage is relatively simple and quick thing to do? Yeah, image recognition is everything but that. Combing through the vast amount of footage people stream every day and checking whether any second of said streams is a shooting or not is going to take a few orders of magnitude more computational resources than determining what ad to show. Given how this kind of event is exceedingly rare, running all streams through such system would be a bigger waste of power than bitcoin.

The alternative

There’s two other ways a social media site could reliably moderate streams is by hiring people to watch them as they happen. This also would require a lot of manpower and wouldn’t come cheap. The other way to handle that is for sites to disallow streaming (and/or posting videos) altogether unless you’re verified, which brings us to both issues that relate to freedom of expression, as well as whether the collateral damage is worth it. At the end of the day, the question arises: is it worth to waste so many resources? Is the vast collateral damage worth causing the next wannabe livestream shooter to throw their camera away and commit the shooting anyway, with the only difference being one less liveleak video? Is it worth getting closer and closer to 1984/China-level censorship (with the only difference being that the censorship is performed by corporations rather than governments)?

There’s only answer that’s objectively correct in this case: “No. It is not.” People pulling ads over Facebook and Google not having systems to prevent a potential shooter from streaming their shooting are outright unreasonable. And possibly the worst thing about that is they don’t even realize it.

100 Groschen

This post should have really ended in the previous chapter, but this entire debacle with pulling ads only serves to highlight that internet’s reliance on ads is a bad thing, to the point even one of the original creators of the world wide web, Jean-François Groff, wonders whether things would be different if internet had some micropayment infrastructure built into it from the start.

At the moment, it seems that Brave‘s BAT token thing seems to be somewhat promising step in the direction where advertisers don’t matter. On the tin, BAT says users earn tokens by watching ads, and then give out said tokens to the sites they visit. Hopefully one will be able to buy those tokens on their own in the future, meaning websites will profit off your visit even if you don’t watch ads. Here’s to hoping that this project gains some traction and sees widespread adoption soon.

Orc Histories: Volume I

Author’s note: yes, I accidentally spilled my homebrew all over my 5e Monster Manual. What you gonna do about it?

Chapter 1: Creation Myth

There was a time before orcs. In that time, only men, elves and dwarves walked the world. Their gods felt a sense of pride and accomplishment turning the world, their prized sandbox, into a landscape filled with those who worshiped them.

Not all liked that. Nerull, god of death and darkness, saw the world and — being Nerull — that the men and elves and dwarves need to go. For that, he needed an army: an expendable war force that would do his bidding. With that in mind, he started capturing those of other races and slowly corrupting them into a form that would befit his goals.

Thus, orcs were created: big and strong — as strong as possible! — and with reduced capacity to think for themselves, as Nerull felt this was the easiest way to ensure that the orcs will do his bidding, and to not fear death. There were only a few that were granted cunning and wits, and they had to prove they deserve them.

Chapter 2: The First Conflict

Nerull unleashed hordes of orcs on the unsuspecting world soon enough. Quick to breed, orc-kind became a force to be reckoned with and a great threat to other races. As such, Nerull and orcs quickly caught attention of other gods. Corellon Larethian stood up for elves, Pelor for humans, Moradin for dwarves. Yet even with their powers combined, the conflict ended in a stalemate: for a long time, they were not able to defeat Nerull and the hordes of orc fighters.

Eventually, the three gods cooked a plan: Pelor and Moradin were to distract Nerull — and with Nerull’s attention directed elsewhere, Corellon was free to mess with Nerull’s creation using means of magic. There was great many tricks that Corellon would try to use, and the first to work was the one that changed the way the orcs are born.

Corellon cast a curse on the orc-kind, that would cause all orcs be born fighters and with little desire for a bond with a child-bearer, in a bid to end the orc-kind by making sure no kid-bearing orcs are ever born again. The curse did not succeed entirely in this way: while it did reduce the number of child-bearing orcs to be born, it did not prevent that from happening completely. While a rarity, child-bearers were still common and fertile enough for the orc-kind to continue.

The curse had some unforeseen consequences that carried a benefit for Nerull as well: with fighters (with few exceptions) not being interested in fucking child-bearers or anyone else, they could finally dedicate all their brainpower to their true purpose: fighting and killing.

Effects of this curse still last — and can be seen clearly — to this day.

Chapter 3: Gruumsh’s Rebellion

Pelor, Corellon and Mordin did not like the new development. While the orc numbers did decrease at first, Nerull quickly dealt with the problem. While he was not able to reverse the curse, he managed to work around it in different ways: by making child-bearers only good for bearing next generations of orcs, and restoring will to fuck at least in those who rose to a place of power within their tribes.

The three gods had to form a new plan. The next worthwhile idea was presented by Moradin: his plans was to grant one of the orcs wits and wisdom — enough to realize that the orc-kind is being taken advantage of. With no better ideas at the time, Pelor and Corellon agreed.

After some consideration, they picked an orc while Nerull wasn’t watching: a promising fighter, named Gruumsh, and followed through with the plan. One day, Moradin appeared before Gruumsh, and granted him wits and wisdom to see how orc-kind was exploited. The relevation made Gruumsh mad, and Moradin was quick to offer him a deal.

He was to convince the orc-kind to rebel against Nerull and free themselves from his rule. As an award for his success, he was promised a godhood and a place for orcs to live — the latter under condition that orcs won’t war other races and expand beyond their lands.

The deal was made, and Gruumsh kept his end of it: he started raising a horde that fought to free themselves from Nerull. His campaign was a great success, since most tribes didn’t appreciate being used by their creator. Not all orcs wanted to join him in fight against Nerull and even raised arms against him — but at the end of the day, with almost all the orc-kind under his banner, the tribes resisting the freedom were defeated. The orcs were finally free from Nerull.

Chapter 4: Gods’ Betrayal

But the gods had no intentions of keeping the promises they made. When the war against Nerull was won, Gruush waited and waited to be given godhood, he waited for Moradin to show up and make good on the promise. But that didn’t happen.

Eventually, it was Nerull who came to him in the darkest hour of the night and told him the truth: that the gods he made a deal with were not planning to give him neither the godhood, nor the lands for orcs to live in. Gruush didn’t believe him at first: he still remembered very well that Nerull has made orcs to serve him and his evil means and thought Nerull was trying to use him for his intentions. Nerull replied by irrevocably granting Gruush the godhood he desired, and said: ‘‘Then come with me, and see it for yourself.’’

Gruush followed Nerull into the domain of gods, where all the gods were gathered around the world map, crafted upon a sphere. He reminded the gods what he was promised, and tried claiming the mountains for the orcs — only to be denied by Moradin: mountains have been taken by the dwarves. He tried claiming forests, only to be denied by Corellon: forests belong to the elves. He tried claiming the plains, only to be denied by Pelor: those were claimed by the mankind. He tried picking some more spots, yet for each and every one it turned out that it’s been already claimed.

This didn’t sit well with Gruumsh: he let out a mighty and furious bellow, cursing all other gods for their treachery. He took his spear and started whacking at the map of the world until it started breaking into pieces, wowing that the orcs will wage the war on everyone forever — a promise the orc-kind has certainly kept well to this day.

Youtube’s copyright shortcomings: [intensifying]

Every now and then, Youtube messes up. Every now and then, someone will go and complain that youtube allowed someone to steal monetization off their videos and did nothing to fix the issue — and when people aren’t complaining about bogus copyright claims by copyright trolls or unjust demonetization, video (and even channel) removals, there’s some twats running around slapping illegitimate DMCA takedowns.

Major incidents usually happen once every few months, prompting some angry posts on social media. However, it has never happened that we’d get three major ‘offenses’ in about the same week.

The Fat Rat incident

Normally, small channels are the most vulnerable to having their monetization stolen by copyright trolls. However, it turns out that big names aren’t exactly immune to that sort of thing, either.

TL;DW: TheFatRat (a fairly popular producer, who releases songs for people to more or less freely use in their videos) had his song effectively stolen by some Columbian “music label” and the story goes like this: some twat made a remix of TheFatRat’s song, uploaded it to youtube, his label then decided to steal monetization from TheFatRat.

“What a douchebag,” most would think, and go to condemn both the guy who made a bootleg remix as well as his label. But wait, it’s even worse.

Turns out that the guy who made the remix wasn’t really a twat. It seems that he was decent enough to include proper credit. Not only that, but he claims that he doesn’t even know the label that stole monetization from TheFatRat

Link to twatter.

Youtube’s response so far basically, as usual, amounts to ‘go fuck yourself’. However, you don’t even need to use any copyrighted material in order to get a bogus claim.

The Bohemian Rhapsody

Remember the guy who made that Why is everyone lying about Bohemian Rhapsody video? Yep. He got claimed too.

Moral of the story: get some lube. If music (and movie industry, and until very recently Nintendo) decide to steal your ad revenue you can only get bent and do nothing.

DMCA As A Censorship Service

Youtube always siding with people claiming copyright infringement means that you can effectively use it to censor anyone saying shit you don’t like with absolutely no consequences. I mean yes, theoretically you could get sued, but in reality that’s one thing that isn’t going to happen at all.

Which means that if you’re a shithead (or a scam artists, or both) who can’t handle people criticizing you or the product you’re making, you can just have them wiped off the face of Youtube

And that’s exactly what happened when someone pointed out some serious problems with a game Escape from Tarkov.

And then they even doubled down, admitting they did it and explained why.

The worst thing: nothing can be done about that

The rules that allow all this were basically written by the music industry “because piracy.” And while Youtube could do things that would help content creators, they really don’t wanna. It would cost them money and it’s really against their interests

This brings us to one of the problems that cause this situation: Youtube has monopoly, and any emerging competitor will not be able to compete with it. Some have tried —, vimeo, dailymotion, liveleak — but they all only found their niche (liveleak — videos of bad accidents, vimeo — art), some have closed down (, some have had their funding cut because over-zealous leftist normies (bitchute) and some are currently considered ‘geek territory’ because term ‘open source’ scares people for some reason (peertube).

Spain forget to check themselves, wreck themselves

So here’s a fun thing that happened today in the Spanish-Catalonian dispute. Catalonian leaders stated they want to follow the ‘Slovenian way’ to independence. Spain was quick to reply with: “ye you mean that violent conflict that ended dozens of lives?” Meanwhile in Slovenia, Slovenian foreign ministry invites Spanish ambassador to have a much-needed history lesson.
The abstract of the history lesson goes somewhere along these lines:
  • Slovenia to Yugoslavia: “gib independence”
  • Yugoslavia: “No.”
  • Slovenia: “But we insist.”
  • Yugoslavia: invades
  • Croatia and Bosnia: are also tossing shit around at the time
  • Yugoslavia: decides that waging war against Slovenia isn’t too viable when they also have to deal with Bosnia and Croatia, retreating from Slovenia only 10 days after invading
  • The end.
Which leaves us with two explanations for behaviour of Spanish politicians:
  • Spanish politicians are uneducated twats in a dire need of a history lesson
  • They had their history lesson, this is just them issuing a low-key threat to Catalonia
Knowing how badly Spain is reacting to Catalonian independence, both seem equally plausible. Oh and by the way: it’s okay to not know the history of every square inch of the planet. Nobody needs to know the entire history of every little country on the planet. But if you are going to make a reference to it, then at least check the facts. It’s really not that hard.

How to make speech bubbles draw themselves: a story of pain (part 3)

In the part two of this saga, we’ve discovered that not using brute force is not gonna be an option. After our first attempt at brute force failed miserably, we’ll have to find another way.

Me orc, me smash: Brute force revisited

Upon review, it turns out that our first solution was actually kinda close to working. Our algorithm kinda looked like this:

  1. Find the center of the ellipse
  2. Find aspect ratio of the text
  3. Assume that the aspect ratio we found is the same as the aspect ratio of our ellipse
  4. Squash text into the square and draw a circle around it
  5. Calculate the radius of the circle using maths
  6. Unsquash the circle, get ellipse (or two radii that define it)

The obvious problems with this approach were:

  • assumption under point #3 is incorrect
  • this means the radius we calculated was also wrong, and often too tight

We can work around that. We only really need to add very little on top of what we already have:

  1. Calculate radius of the circle using maths
  2. **Increase that radius by some factor in order to give us some breathing room**
  3. Unsquash the circle, get ellipse (or two radii that define it)
  4. **Try to make ellipse smaller, one small step at a time**
  5. Repeat #8 a few times, use the best result you get

Steps 8/9 can be done using a kind of binary search, and it goes roughly like this:

  1. Calculate whether all points are in the ellipse for given radii.
  2. If all points are inside the ellipse, decrease radii for half of a step
  3. If any of the points are outside the ellipse, increase radii for half of a step
  4. Decrease step by half
  5. If step is sufficiently small, you can stop
  6. If step isn’t sufficiently small, go back to #1

In our case, we have two ‘steps’ (each for one of the radii). Before starting our algorith, we determine two values for each of the radii:

  • “Radius can’t be bigger than this” number (e.g. width of a given line of text)
  • “Radius can’t be smaller than this” number (e.g. half of the width of a given line of text)

Step is the difference between the two (different for each radius). We use the bigger of the two numbers as our radius.

This works great, but we can improve it even further. Inside every step, we can try decreasing size of one radius while keeping the other radius the same. This can help us find smaller, better-fitting ellipses at the expense of some extra calculations (to the tune of O(n²)).

Trying it out

Now that we wrote the code, it’s time to try it out. Results ended up being slightly disappointing:

Yikes. That’s worse than our previous test. We even managed to fail to draw a rectangle properly.

What is worse: there doesn’t seem to be neither reason nor rhyme to why things don’t work. Our brute force approach was used at least five times and has two failures (where bubble is way too small). Multiline texts — the ones that very probably don’t use the bruteforce approach at all — are often off-center and sometimes even too small (all off-center bubbles are too small, so text doesn’t fit in the ellipse):

Those four texts must be related to Cinderella.

What gives?

Upon closer examination, it turns out that some ellipses that should be drawn with brute force method weren’t drawn by brute-force method. Secondly, despite determining ellipse’s radius by brute force, we still always use our matrix to determine one or both center coordinates. Our ‘high maths’ approach is giving us slightly suspect — and possibly even wrong — results.

The one thing to consider when writing code is that computers are generally fairly terrible with very tiny (and very big) numbers. The tinier your number (we’re talking anything past fifth decimal), the less “accurate” it is. The values the matrix calculation spat out contained some very tiny numbers. When those numbers were used to perform further calculations, the errors grew and we got garbage results.

Let’s forget the ‘high maths’ approach for a while and try to brute force everything.

Giving brute force another try

Step 1: determining the center of the ellipse

This one is going to be easy. We still only work with 4 points at the time. To get the ‘center point’, we find the average of the four coordinates. Then, we try to find the intersection between the lines connecting the points at the opposite sides of the quadrangle the four points form. If the point of intersection is mirrored over the ‘center point,’ it gives us the center of our ellipse.

Step 2: apply smash, remove smart

We feed the center of the ellipse we got from step 1 into the brute force algorithm we discussed earlier, run some test and …

So close, yet so far. Something crashed the script on the last bubble.

Good news is: brute force does find better results than attempt at using high maths. No bubble is drawn off-center, all bubbles are correctly sized. The reason for the crash is a weird point selection: one of the diagonals (in at least one of the 4-point subsets of the last bubble) is vertical. In order to calculate the center of our to-be-ellipse, we need to know the slope of thes line between the opposing sides. There’s a bit of a problem though: if you’re trying to calculate the slope of a vertical line in a coordinate system, you’re going to faceplant into a division by zero.

Computers don’t like dividng by zero.

Trying to find an intersection in this point combination is going to be problematic.

We can quickly see another thing: if we try to determine the center for our ellipse using these four points, we’ll just get less-than-optimal solution. That means we can skip it — all it would do is waste our time.

Let’s see if that fixed our probem:

And all is right. As far as performance goes, “stopwatch test” says brute-force approach isn’t really that much slower than the “proper”, “high maths” approach.

This leads us to the conclusion:

Lots of people love the “work smart, not hard” approach to things. Sure, using a little bit of brainpower to avoid using a lot of force is nice. But let’s not forget that sometimes, the opposite applies: a little bit of brute force can save us from using lots of brainpower.

Moral of the story: don’t overthink your programs, I guess? Sometimes, simple is better and ‘approximate’ is good enough.

You’re looking at one or two weeks of my free time going down the drain. Just like that.

How to make speech bubbles draw themselves: a story of pain (part 2)

When we left off last time, I still thought this wasn’t going to be that bad. I was wrong.

Matrix: reloaded

So we’re back to square one and I’m looking at the first answer about my problem that I’ve found over at math stackexchange. When I first saw it, I thought I haven’t watched enough Rick&Morty to understand it, but after playing around with it for way longer than I should have I started figuring shit out.

If you plop 4 points into the following equation:

ax² + by² + cx + dy + e = 0

And solve the system of those four equations, you should notice that the variables ‘a’, ‘b’, ‘c’ and ‘d’ are all some fraction or multiplier of ‘e’. Even without knowing the value ‘e’, we can calculate the center of the ellipsis. If we want radius, we need to know ‘e’. Assuming ‘e’ is -1 seems to do the job the way we wanted, though.

Since our convex hull often contains more than 4 points, we try to calculate the ellipse for every combination of 4 points (out of all points on the hull). Note that because we’re lazy, we don’t calculate the hull. We just take upper two corners from each row in the upper half of text and the bottom two corners from each row in the bottom half of text. If the text has odd number of rows, we include all four corners in the convex hull.

All edge points are marked with a circle.
— point not on the ‘convex hull’, therefore we ignore it.
— Points we assume are on the convex hull. No biggie if they aren’t as we throw out garbage results later

We calculate radii for each combination of 4 points that we have. We check if the new ellipse contains all the points of the hull (either inside or on the edge). We reject the result if it doesn’t. If we don’t reject the result, we compare it with the last result we didn’t reject. If the ellipse is bigger than the last result, we reject it. If not, this is our new result. Repeat until you’ve ran out of combinations.

It fits, more or less. There appears to be some rounding/off-by-one error down there at the bottom, but nothing that’s terribly problematic.

Sooner or later, though, we run into a problem. What if ‘c’ and ‘d’ are free variables instead of ‘e’? This happens if any of the four points are horizontally or vertically symmetrical relatively to the center of the ellipse. For example, if you plug points 0,0; 4,0; 0,2; 4,2 into the equation, you’ll find that ‘a’ is some fraction of ‘c’ and ‘b’ is some fraction of ‘d’. You can still calculate center from that, but you can’t get the radii. Even worse is the case of 0,2; 2,0; 4,0; 6,2: symmetry across only one axis means you can only get one coordinate of the center because there’s infinitely many solutions.

Since we’re after only one specific solution, for us ‘infinitely many solutions’ equals ‘no solution.

Forsaken cheats

In the second example from above, we could do some additional maths in order to find the center. We’re only interested in the smallest possible ellipse, so we could calculate some limits in order to get the other center coordinate. But word on the streets is that cheating is easier and could get us results that are close enough to what we want.

Turns out breaking symmetry isn’t too hard — we just need to ensure that points in the left and right halves don’t share the same ‘y’ coordinate, and points in top and bottom halves don’t share the same ‘x’ coordinate.

The first bit of this task can be easily achieved: since every row has two points with same ‘y’ coordinate (and since ‘y’ coordinate can’t repeat across multiple rows), we just need to shift one point a bit up and the other a bit down (or keep it at the same place).

Shifting ‘x’ coordinates is a bit more problematic: two different rows can absolutely contain same ‘x’ coordinate — and what is worse, if we shift the ‘x’ coordinate in any way, we may create the situation we’re trying to avoid. However, we know the following things:

  • point coordinates are whole numbers only (We get points by reading pixels, and there’s no such thing as ‘half a pixel’)
  • only points in the opposite rows are required to have different x and y coordinates

— point not on the ‘convex hull’, therefore we ignore it.
— Points of the same color aren’t allowed to share any coordinate.

If two neighbouring rows (e.g. top two rows in text with more than 3 rows) have points that share the same ‘x’ coordinate, it doesn’t really matter because ellipse containing those points would be rejected for being too small anyway.

This allows us to easily apply required offsets:
* upper left: x -= 0.5, y -= 0.5
* upper right: x -= 0.5
* bottom-left: y += 0.5

So I thought I could do it by shifting points a little outward. Turns out that two-line and one-line rows disagree. At the end of the day, “losing” half pixel of space won’t really be noticed when bubble is more than hundred pixels across most of the time — and when it’s not, the radius is still in high double digits. So let’s change that a bit:

  • upper left: x -= 0.5, y -= 0.5
  • upper right: x -= 0.5
  • bottom-left: y += 0.5

Not quite what we want, but better than what we had before.

Let’s try that out a bit more:

Oopsie whoopsie. Fucky wucky.

Turns out I spoke too soon.

The Right Way™

Sometimes, we don’t have enough data to determine where the center is. Sometimes, we will only get enough data to determine one of the center coordinates. For example, if you only have four points to go off, and if said points would form a symmetrical (acute) trapezoid they were to be connected with lines — and since our text is centrally aligned, that happens almost every time we want to draw a bubble around two lines of text — you can still determine horizontal center.

Turns out this comes out handy: we can determine one of the coordinates using the kind of “cheating” approach we used before, but with some twists:

  • We split points in two groups: those to the left and those to the right of the horizontal center (top and bottom if we have the vertical center of the ellipse)
  • Find the vertical center of the text (the spot halfway through the topmost and lowermost text edge)
  • Find the longest diagonal (upper left to lower left or lower left to upper right)
  • Find where the diagonal crosses from one half to the other, and flip that point over the vertical center of the text

The last step is important because longer lines will move the center of the ellipse away from center of text, towards themselves — but the point where the diagonal intersects the horizontal center is going to be offset in the opposite direction.

We need to account for the fact that center of the ellipse is going to gravitate toward longer lines.

Once we have both coordinates of the center, we still have some leftover data from the matrix that we can use to determine both radii.

However, this approach doesn’t cover all the cases (it fails at least one), and the ‘offset corners by half a pixel’ way of dealing with things doesn’t seem to harm it, so we’ll just keep both in for the time being.

All in all, we’re progressing somewhat nicely. There’s some work to be done when determining the anti-jag parameter of the rectangular selection (but that — as well as padding — will be user-provided arguments/options). The only thing we have to deal with now are the bubbles with one or two lines, where our current tactics for determining the bubble size fails.

Testing grounds. Things are mostly fine, except the bit where my script won’t handle the red bits.

Turns out that — spoiler alert — the brute force approach is the only approach that will consistently work. Maybe it should be revisited.

How to make speech bubbles draw themselves: a story of pain (part 1)

Every now and then, I sit down in front of my computer and start making a comic. It follows a very similar premise to DM of the Rings and Darths&Droids — that is, take a movie (in my case, How To Train Your Dragon) and pretend it’s a D&D session — except my work is much less original and not that good, probably. Oh well.

If you’re making any sort of comics, you’ll probably have to draw a ton of speech bubbles. Mind, drawing basic speech bubbles isn’t that hard: you use the oval selection tool, select an area and fill it with color. But boy does it take time. The more of them, the longer it takes — and boy do some pages feature a lot of them.

Just to illustrate how bad it can get. Now admittedly an episode normally won’t have this many bubbles, but that doesn’t mean drawing speech bubbles isn’t a colossal waste of time.

Because we like to work smarter, not harder, the question pops up: why don’t we make a script that would draw speech bublbes for us? I’m using GIMP anyway, and GIMP has plugin support. ‘‘This shouldn’t be too hard,’’ were the famous last words as I opened visual studio code on that day about two weeks ago and got to work.

Drawing rectangles is easy. Drawing ellipses is hard.

Comics often use two kinds of bubbles: there’s bubbles used for narration, which are often rectangular; and there’s bubbles used for speech, which are generally elliptical (more or less).

Determining borders

If we want to draw any kind of bubble (be it rectangular or elliptical), we must first figure out where to place it. This is the easy part, because:

  1. we use GIMP and put the text for each bubble on its own, separate, transparent layer. That’s one of the important assumptions that we’ll make (especially for elliptical bubbles): we don’t reuse text layers for more than one bubble, and the layer is always transparent except for text.
  2. images and layers are, in general, grids of squares (pixels), where each square is colored with a different color. This allows us to borrow some tricks from Ultrawidify: we’ll check every pixel of every row, and every pixel of every column for the presence of non-transparent pixels.

If we keep track of where the first non-transparent pixel was found for every row and column, we can figure out where the text starts and where it ends. If rows of text don’t overlap each other, we get the bounds of every row of text in the layer. And when we know that a row of text starts at line 32, ends at line 64, starts at column 3 and ends at column 125. That gives us 4 corner points per line of text, and that’s enough data to draw a rectangle. The vertices are at 3, 32; 125, 32; 3, 64; 125, 64. The procedure is so simple it doesn’t even deserve its own heading (although there is a few minor, seemingly simple improvements you can make to that). At least compared to what’s about to come.

Ellipses can honestly piss off

Do we even know what we’re trying to do?

Yes, actually. We want to draw an ellipse around a set of points, where:

  1. All the corner points must be inside or on the edge of said ellipse
  2. Points must be as close to ellipse edge as possible

In order to draw an ellise, we need to know:

  • width and height of the ellipse
  • center of the ellipse (or more accurately, upper left corner¹, but we can get that from width and height of the ellipse)

¹In computer graphics, the coordinate system is flipped over horizontal axis compared to the coordinate system used most everywhere else.

because those are the parameters GIMP’s ellipse selection tool takes. We already know the points that represent the edges of text. What we need to do is to take those points (bunch of pairs of x,y coordinates) and somehow convert that to parameters of the ellipse that will satisfy the two rules outlined above.

Computers are very good at two things: logic and maths. This means we need to tell it how to calculate the center, width and height from those points. Because I don’t recall that lesson from my math classes, I went to every programmer’s best friend (stackoverflow) and discovered that — spoiler alert — this is either a) more or less impossible or b) requires diploma or master’s degree in maths.

I studied computer science. We had maths, but not that kind of maths.

Time to cheat

First of all, we subtly change our second requirement. We don’t require that the corner points are as close to the edge of the ellipse anymore, instead we focus on trying to draw the smallest ellipse possible. It’s less than ideal, but we’ll have to live with that.

It’s a subtle difference that only matters in edge cases like this. ‘Points as close to the edge as possible’ will give us a bigger ellipse overall, which is sometimes desired (if the upper portion of the speech bubble were to be covered with something). ‘Smallest ellipse’ produces lots of wasted space around the bottom line.
Dots serve as a rough illustration of what the script would consider to be a corner point of the text.

After we’re done revising our requirements, we head back to google and look up the equations for the ellipse.

x = a * cos(t)
y = b * sin(t)

Where x, y are coordinates of a point on the ellipse; a, b are the length of the primary and secondary radii. We can do something with this. We can calculate where the center of ellipse will be. We just calculate where the middle point of every opposing pair of corner points is (e.g. the opposite point of upper left point in the top line of text is the lower right point in the bottom row of text). Since each pair of corner points may give a slightly different center, we take the average of those centers. Now that we know where the center is, we can use some high school maths to calculate the angle between straight line from center to a given point and the horizontal axis, and we do that for every point. Biggest ellipse will contain all the points, and we will have our answer.

Except t is not the angle to our point. tis the angle between horizontal axis and the point where our point would be, if the ellipse was squished (or stretched) into a circle. We can squish (or stretch) ellipse into a circle by multiplying (or dividing) one of the coordinates with the aspect ratio of the ellipse.

Do we know the aspect ratio of the ellipse? No.

We know the topmost point of the top line of text, we know bottommost point of the bottom line of text, we know leftmost and rightmost point of the longest line of text. We can get width and height from that. We can use that to calculate an aspect ratio.

Is that aspect ratio the same as the aspect ratio of the ellipse we want? Tests concluded that no. This is not the aspect ratio we’re looking for. Our final result looks something like this:

White ellipse is what the script did. The selection has same dimensions than ellipse, but is placed roughly where the ellipse is supposed to be. Red lines represent what our script considers to be a line of text.
Red line should be entirely within the ellipse (with at least 3 pixels to spare in the vertical direction, and 7 pixels to spare in horizontal). But the red seems to poke out for some reason.
And not only does the ellipse fail to contain the lines completely, it’s also offset to the left and a little bit to the right.

Can we fix the aspect ratio with some brute force? I could write another paragraph on how this was attempted, but long story short: turns out we can’t. We’d need more data to draw the ellipse we want.

Oddshot with sound here.

Bummer. Turns out cheating doesn’t pay (yet). I guess we’ll have to do things the proper way™.

Of Tabletop RPGs, Railroading, and Video Games

So I’ve recently stumbled over this meme.

Of course, this was captioned with ‘TTRPGs > Video games’

It’s very hard to resist rising up to the challenge in hopes of earning that delta — especially given how everything about that meme is wrong. The long story short is that this meme incorrectly assumes two things:

  • video games railroad players
  • this isn’t an assumption per se, but something tells me that whoever made this meme fundamentally misunderstands the problem people take with being railroaded

And we’ll handle those two problems in this order.

Side note: Am I getting too triggered over a meme? Possibly, but there’s some potential discussion to be had about this issue ~~and I’ll probably get to recycle these arguments on reddit within the next 2 months~~.

Of video games and railroads

The first thing in the picture that’ll trigger most nerds like me is the hidden implication that video games are more or less the same. Truth is: they aren’t — if anything, they’re the most diverse form of media to date — and all “railroad” to varying degrees.

  • You have Sandbox games and simulators. Think Sim City, Cities: Skylines, Minecraft, Terraria, Factorio … are there rails? Yes, for you to place them. Are you being railroaded? No. Can Tabletop RPGs (TTRPGs) do any of that? Not really. Yes in case of Sim City, actually — reddit and forum threads by DMs saying their players want to play a city builder who ask for advice are surprisingly common   but your DM will have silver hair by the end of the month if he doesn’t already.

This is probably not the kind of railroad(ing) you’re thinking about.
  • Stealth games like Stxy and Thief, or “optionally-stealth games” like Deus Ex and Assassin’s Creed (especially the early ones) tend to have fairly linear stories, but levels tend to offer multiple paths and multiple ways to solve a problem. And even in the story department, you sometimes don’t get railroaded as much as you think — original Deus Ex would be a decent example of that.

    While we’re talking of stealth: stealth in TTRPGs is hard to pull off well, and any stealth system you cook up in a tabletop setting can’t hold the candle to the video game thing due to the inherent limitations of tabletop RPGs.

  • Non-turnbased competitive games like CSGO, DotA2, League of Legends, Rocket League … there’s not much rails there either (except if you play Train or Overpass). There’s about as much railroading going on here as in your average sport. And it goes like this: you get a map (the game equivalent of a dungeon) and then you get to outsmart the other team the way you want. There’s nobody that will prevent you from rushing mid on Dust 2 the same way a bad DM would prevent you from checking out a random room in the dungeon for no reason. That’s the kind of experience TTRPGs can’t offer, at all.

(Note that Office and Canals aren’t excluded because of rails, they’re excluded because they’re trash.)

  • Then you also have various kinds of strategy games. Say, Command & Conquer in general, Civilization series, things like that. They’re all pretty open-ended with nobody telling you what to do. These kinds of games are generally impossible to railroad as well.

  • Keep Talking and Nobody Explodes? Okay, you can have that in a TTRPG pretty much verbatim. I know because I sneaked that into my last session, and it was great. 11/10 would recommend.

  • Next up on the list are open world RPGs. Things like The Witcher 3, which – again – doesn’t really railroad you all that much, judging by the first 18 or so hours.

    MMOs like World of Warcraft and Guild Wars 2 should also get a honorable mention here. In general, they are not really that heavily railroaded (at least not until the end game stuff, for which I can’t speak). Neither of the two games will prevent you from going to zones way above your level (or way under your level). You can pick and choose what quests you’ll be doing – especially in WoW, bit less so in GW2 cos story missions. Most quests tend to be very simple in both games, though.

And then there’s everything else. There’s a bit more linear games that don’t give you choice, there’s linear games where your decisions end up having an effects. There’s games that switch between A and B plots, with decisions that tend to have an effect on the outcome of the story (The Banner Saga). There’s tons of racing games which cover everything from hyper-realistic simulation to stuff that’s about as unrealistic as it can get, there’s sports games   and I’m not sure term ‘railroading’ is even applicable to any of those.

The problem with railroading

At the end of the day, not liking railroading boils down to one thing:

People don’t like it when their choices in games don’t matter.

Yes, even in The Witcher the game will give you about three predetermined options to pick from when making a decision; and yes, some may consider that railroading. But the fact is: the game won’t borderline make that decision for you. Furthermore, that decision may or may not have consequences later down the line, and at the end of the day nobody will consider that the game is railroading them.

Meanwhile, when you’re being railroaded by your DM, none of that holds true: you’re often being borderline forced to solve the issue in one particular way, and you know that your choices matter about fuck all.

But what about linear, single player games like Half Life and Portal and Spec Ops: The Line, you ask, what’s with them? You don’t get to choose in those games.

True. You don’t. Since people don’t get to choose, they can’t feel like their decisions don’t matter. Okay, that last statement isn’t completely true, but it’s close to the truth. This is not inherently a problem with railroading, but it helps explain why people who complain about being railroaded in D&D might go and outright praise games like Brothers: A Tale of Two Sons.

Expectations vs reality play a massive role in whether you’ll consider linearity a railroad

How a game is advertised has a massive effect on how railroading is perceived. Portal games, says on the tin: “Linear puzzle solver.” Play the game, you get linear puzzle solver. Expectations == reality, things check out. Spec Ops, The Line. Tin can says “linear shooter with generic gameplay, but story is strong and the game is outright nasty towards you.” You play the game and that’s what you get: It’s a shooter alright, but the story is worth the praise and the game does make nasty jabs directly at you during the loading screens. Expectations are fulfilled once again. Then you ~~open up the Player’s Handbook which tells you repeatedly that D&D is a game of player choice in the first three pages~~ I’m just kidding, what kind of player would read the PHB even if they could read it for free? Mine certainly didn’t. Instead you listen to your DM, or reddit, or internet in general try to sell you the game by stating that you, the player, gets to decide what to happens in that D&D game. So you’re like, cool, let’s play. And you play the game, only to discover that you don’t actually get to call the choices. Being salty is more than understandable in that scenario. (Worth pointing out, because one of my groups didn’t get the memo: shit decisions you make having shit outcomes isn’t railroading).

I never would have thought I could replace my entire D&D group with a single robot.

Overly obvious railroading is also frowned upon in video games as well

The Mass Effect 3 thing might not be a typical railroad, but it goes to show that even people who otherwise like video games don’t like when they don’t get the choice they were promised, or when their choices don’t have the impact they were promised. Mass Effect 3 promised the choices you made in the first three games would matter in the end, and they did somewhat … right up until the last 30 or so minutes of the game, where everything pretty much boiled down to the color of the ending cutscene. The internet was up in arms about that for at least a few months.

And that’s just one example: people will complain about railroaded missions in video games pretty much regularly. If the game does this thing where you can see enemies from far off and could kill them from afar without having to engage in a massive close quarters combat, but you ultimately can’t because the game pretty much makes them invulnerable until you trigger a cutscene which triggers a fight … Do that too much, and players will complain. Guaranteed. With Skyrim, people got uber-butthurt because the game wouldn’t allow you to kill the people who told you to kill Pathrunaax. In fact, they didn’t like it so much there’s a mod that fixes that.

So what have we learned today?

The image that caused all of this is mostly wrong.

Also, I want my delta.

Epistle 3, D&D edition

This post has been migrated from its old post and backdated according to the file timestamps. Backstory and references are explained here).

Dearest Players,

We hope this letter finds you well. I can hear your complaint already: “Sergor’s company! We haven’t heard from you in ages!” Well, there’s plenty of excuses to be had, but there’s no sense crying over every mistake. We just keep trying until we run out of cake. The quest gets done and you bring some loot home for the chars who are still alive. Truth be told, we’ve been trying to reach you for nearly four months now, and only recently with anything that resembles success. We know that a lot has happened since the last letter and that you’ve been eagerly awaiting the next update, so let us give you a hastily update.

When we sent off the last letter, we’ve just finished fighting a group of bandits in their lair. Fearing that we haven’t slain all the bandits (given we entered the mines during daytime, we figured some of the bandits could be outside. They could return at any time, catching us off-guard while we rested), we quickly retreated out of the mine and wrote the letter in the safety of the forest while resting from the fight. Then, we followed the path — no detours this time.

We eventually came to the—

[most of the text in the next few paragraphs seems be smudged to the point it’s unreadable]

After making our way across the bridge, we quickly came upon a small town, barely anything more than a square — still, we managed to find a messenger, to whom we gave the previous letter. After wandering around the city for a bit, we found a noticeboard with all sorts of contracts. One of those contract in particular has sent us on a path we never expected.

The contrast was posted by the town’s major, who was a shady character. We were to take a package to Crow Rock. We weren’t told about its contents, nor we were allowed to open it. We ended up taking the contract, as it paid well and led us to Crow Rock, a town where we had some unfinished business with a dragon. Somehow, we even managed to beat curiousity, avoiding sticking our noses into the nature of the thing we were carrying.

When we handed the package over and were paid our money, we made our way to the lord of Crow Rock, as instructed by the dragon. We eventually met him, and he gave us a little something for our trouble (after verifying we speak the truth. He even included something for Gmuk!) — but he promised us even more if we help him with the quest.

He explained to us that the King was doing evil things — making deals with orcs and goblins, which terrorized the kingdom for his personal gain. We were also told that the king was looking for a certain magical artifact, that would (by the legends, at least) grant him immense power if he used it properly. We were to find it first and destroy it. The reward was certainly great and appropriate for the dangerous task — not to mention that we were to have a dragon accompany us. We were given some time to think about it, and after a long discussion we agreed to accept the mission. A lot of work has been done for us already: the mages at Lord’s disposal made a compass that pointed towards the approximate location of the artifact (don’t ask us how it worked). The compass didn’t show distance, but were told that the artifact is far away and moving. How far? Nobody knew exactly, but we were told to expect trouble along the way.

Bogdan was kind enough to make a quick sketch of Crow Rock during one of our downtimes.

The trouble has started before we even left: for some reason, Neri called Lore, the dragon, ‘chicken fucker’ one too many times, which resulted in the dragon swiftly helping to solve the elven overpopulation problem to the fullest extent he was able to. This was a problem because she was the only person who knew draconic — but fortunately for us, Lord provided us with a dwarf — Bogdan — who was able to act as a translator. Unfortunately, everything she owned was destroyed in the fire she burned in as well.

We left the town soon after that. The path would be easy if we were riding on the Lore’s back, but we had to walk as the dragon couldn’t carry all of us with all our gear. Thus, we had to walk through the hills. The roads were full of turns, ascends and descents — all of which slowed our progress. He felt bad for us “lesser creatures, uncapable of flight” and walked with us out of solitude. Every now and then, he did take off, into the sky and was our eyes in the sky. He gave us early warning about any orc, goblin, bandit ambushes and encampments, which we cleaned or avoided based on our mood.

I, Kvothe, made sure to keep the spirits up by playing my lute and singing songs. Everyone enjoyed my songs. True, Sergor said that ‘‘[I] can’t sing for shit’’ and that I’m ‘‘an annoying little gypsy that should be thrown off the edge of the world’’ and that he’d ‘‘rather experience Lore burning him to death than listen to me play the lute or sing;’’ while Gar threatned to break the lute on my ass if I keep playing and singing. I’m sure they didn’t mean it and that they really like my performances. Kali also liked my songs. She even had nice words to say about me, telling me that one day I might become a good musician. Bogdan said nothing of my singing for the first few days. I did talk with him on a few occassions though, and after a few days he taught me some of the dwarven songs. ‘‘The best thing about dwarven songs is that they sound great regardless of whether you can sing or not,’’ he said as he taught me. ‘‘After you’ve had enough ale and beer, it doesn’t matter whether you’re tone-deaf or not anymore.’’

Our first longer stop was Bogdan’s hometown, a dwarven town of Vergenband. It was located a bit off the path, on the border between hills and mountains. Some of it was located at the end of the valley (but still in it), but most of it was under a mountain. This left our dragon mostly bored, as he wasn’t let into the mountain part of the town for various reasons. Gmuk was at first not allowed into the town either, as dwarves feared he might steal things. After some convincing (and Bogdan’s good word), Gmuk was eventually let into the town, proving dwarves’ fears correct the first chance he got (fortunately for us and him, nobody caught him. We only learned about his theft later, when on our way again). In the meantime, we enjoyed a longer rest (about a week), did the town some favours, replentished our food supplies for free (turns that Vergenband was allied with Crow Rock). In exchange for our favours we did to the town, we were then directed towards a druid’s. We were also given a letter by the chief dwarf of Vergenband, which instructed druids to provide with with some help.

The stop at the druids was a short one: upon receiving the letter, they gave us some tamed beasts to ride: Bogdan was given a great mountain goat, Sergor a direwolf, Gar a wyvern. I, Kali and Gmuk — even together, we weigh next to nothing — were allowed to ride Lore (although both Lore and Gmuk protested the idea of Gmuk riding him — it took a long time to convince them both). A druid named Joshua Nissan — the keeper of the beasts — also joined us, riding on a great fox.

After leaving the druid’s groove, there was no more planned stops for us. We continued to follow the compass for long days, which soon turned into weeks. The compass was pointing mostly to the north, slightly to the west. Its direction didn’t change much; the landscape, however, did. The hills soon ended. Then, the forests were gone as well: we travelled across the grassy plains, with settlements few and far between. Eventually the forests appeared again, followed by hills again (this time smaller than the ones surrounding Crow Rock) soon afterwards. After crossing the hills, the villages and towns became more common, and the fields were plenty.

The lands were significantly colder, too. This wasn’t a big problem for us: we spent some money on a good set of warm clothes. Direwolf, goat and fox were also protected by a thick skin and fur of their own, but it was obvious that the wyvern and the dragon were not comfortable (apparently the ability to breathe fire doesn’t mean there’s a fire burning on the inside). As we reached a town at the coast of a sea (which the compass told us to cross), we have made a decision to send the wyvern and dragon home. Of course, the dragon opposed and insisted on staying. In the end, the only creature to return home was the wyvern, and Gar had to join Sergor on the direwolf (neither of whom liked that too much).

But as we tried to buy a passage across the sea for ourselves and our beasts, we discovered another problem: our money was all but gone, and Crow Rock Lord’s influence was worth nothing in the town. This meant that we had to seek out a few contracts in order to earn money. Lore also felt like he needed rest; he was also aware that people were curious about him not attacking them and burning their town. He planned to capitalize on that, so he picked a spot near the docks and had Bogdan erect a sign, which said:

’U can’t touch this.’

’Unless you have skrilla, then you can.
You can also scratch my ich. I don’t bite
(if you contribute towards my pile)’

Makes me wonder if Lore knew Duncan, actually. Below that, the sign also said, in draconic:

‘If you can read this, I’ll argue with you about anything. 1 gp / 5 min’

Unsurprisingly, nobody took him up on that offer (as draconic-speaking individuals are few and far between), but by the end of the week, he had a modest hoard of about 30 gold pieces worth of gold and silver pieces.

Our company had a bit more luck: between all the contracts (neither of which was too difficult), we managed to collect about 50 gp. But the dwarf earned the most: he bought a cheap but sturdy longbow, some paint and a small iron rod. He spent the week carving a long, legged fire-breathing serpent into the longbow, using the iron to burn black lines on the surface of the bow and paint to make the serpent which twisted around the bow pop out more. The longbow looked marvelous, and although though the serpent looked nothing like it, Bogdan said it was inspired by our dragon. He managed to find a buyer for the bow before he even finished making it — a rich nobleman bought it for about 1600gp. Lore was mighty jealous when he learned of that.

But at last, we had more than enough money for a while: we could buy passage on a ship and we could buy food. Unfortunately, the last ship big enough to take us across was gone so we had to wait. It took about two for a new one to come. With no other contracts, we rested. Bogdan continued on carving in his downtime, selling his carvings, and Lore continued on trying to make the crowd throw money at him for pets and scratces. They both earned some money — and while the luck with the longbow didn’t happen again, Bogdan still managed to make 50 gp of profit. Lore’s hoard was another 60 gp. Gmuk — who nobody kept an eye on during the downtime — managed to contribute a few stolen items, 20 gp 89 sp in cold, hard coins (which were probably also not acquired in legitimate ways). I tried to do my job by singing and performing in the streets, but unfortunately I didn’t earn much. Across two weeks, I only got about 6 gp worth in coins, although some people — probably mostly the poorer one — also gave me food. I base my assumption about their wealth on the fact that more often than not, the food they gave me was rotten. But hey, it’s the thought that counts.

After two weeks, we were finally aboard the ship. It took another day for the ship to actually leave the port, and another half dozen to land on the other side of the sea. The weather was cold, and as soon as we crossed the mountain formation running along the coast, it became even colder, to the point where sometimes, mornings would show grass covered with frost. Lore didn’t take that well, but he was adamant about not returning. I think we all knew this will spell eventual doom for the dragon, so when we stopped in an outpost which primarily traded furs, we put Bogdan’s money to work. We bought everything they had, hired some help and started making clothes for the dragon. Obviously, people thought we’re ‘‘absolutely retarded’’ — as Bogdan observed — but we didn’t care, and neither did they. After all, our gold was their paycheck. In the mean time, we also bought some warm clothes for ourselves: the tailors claimed we’d be fine even if we made it to the northern edge of the world.

This ordeal delayed us by another week, but eventually the dragon was wrapped in warm furs from head to the tip of his tail. Of course, his clothes prevented him from flying, but he rather didn’t complain as he knew he’d be shown the way home. As we continued to march forward, settlements became rarer and rarer, to the point we wouldn’t see one for days. Forests — which were exclusively spruces at that point — were also getting thinner, eventually yielding way to endless grasslands that were only disturbed by occasional river and small hilly areas.

In one of the valleys of such hills, we fell into a drow ambush. The drow nearly killed Bogdan — he barely made into cover. Once in cover, Bogdan asked the druid if he would throw him his longbow and arrows, saying it made more sense for someone who can’t take much beating to take a ranged role. The druid, of course, disagreed (he had learned a lesson about throwing in his earlier life) and they continued to argue while the rest of us had to deal with the ambush themselves. Fortunately, at least Lore was of help, making sure the fight ended quickly. Bogdan and Josh continued to argue throughout the entire rest that followed.

Eventually, the compass has led us out of the hills again, into the wide plains. The grassland was full of snowy patches, and the nights were now really cold. Too cold for Lore, despite the clothes. In one of the nights, a blizard appeared out of nowhere. Lore, as well as other beasts, used his big body to shield us from cold and snow. The blizard was followed by immense cold. Gmuk fared the worst of the company, with a few frostbites and nearly hypothermic, but he survived.

Lore didn’t. When we woke up, our beasts already shook the snow off them. Lore was completely still, looking like an undisturbed pile of snow. At first, we hoped that he managed to survive, but after pushing the snow off him it became apparent that he’s dead, frozen solid. The prayers were said, to whom depended on which gods one followed (if any). The druid, having no gods to pray to, instead prayed to spirits and the nature. We didn’t have enough time for proper burial, though: with Lore gone, we had to redistribute our supplies among the other beasts (we did salvage the furs in Lore’s clothes, though, in case we needed them). With only three beasts and seven of us, we also couldn’t ride (at least, not all of us). This further complicated our food supply calculations, as we were going to move ahead slower. In the end, we guessed that we can afford to walk forward for a few more days, so we pressed on.

About half dozen days later, we arrived to a land permanently covered with snow, with some low, but pointy and rocky mountains rising out of the flatland. The one we came to first was even populated and had a lot of buildings: big homesteads and buildings that we didn’t know the purpose of (but at the end, it turned out that crops are grown in those buildings). The population of the settlement was about 500 people. All buildings in the settlement were warm — hot, even — which seemed unusual at first, until we were shown pools full of boiling hot water, coming out of the ground.

We agreed on a few days rest in the settlement — this time, we kept our eyes on Gmuk at all times, so he wouldn’t try to steal. Bogdan and Sergor climbed the mountain on which the settlement was built. From the top, they saw other mountains, shaped just like the ones we were on, except smaller. One of them featured a camp of sorts. This warranted a second look. We were all but ready to travel closer, but the people of the settlement gave us a spying glass, so we could observe from afar. Sergor and Bogdan then climbed the mountain again, observing the encampnent with the spyglass. They told us they saw ship in the middle of the settlement. This seemed strange and unbelievable as well, but the locals told us more about the ship: it’s called Naglfar and is said to harbour the undead. This is not at all encouraging. Especially not since the compass seems to point at the ship (or at least to the encampment surrounding it). Bogdan and Sergor double-checked: they rode their beasts around for the entire day, but the compass kept pointing at the ship and encampment.

So this is our message we’re sending you, we hope you see it (locals promised they’ll include it on the sledge-train that leaves for a trading outpost closer to the sea in a few days). In the next few days, we’ll try to infiltrate the settlement and destroy the artifact hiding in it. We don’t know whether we’ll be successful. We surely hope that you will be hearing from us again, but a part of me fears — as the dwarf would put it — this could be the last letter we ever send your ass.

But seriosusly, see you next time. Hopefully.

— [Kvothe’s signature]
— [Sergor’s mark]
— [ᛒᛟᚷᛞᚨᚾᛋ᛫ᛋᛁᚷᚾᚨᛏᚢᚱᛖ᛬ᚢᛋᛜ᛫ᛞᚹᚨᚱᚡᛖᚾ᛫ᚱᚢᚾᛖᛋ]
— [Gar’s scribble]
— [Gmuk’s fingerprint]
— [Kali’s sign]
— [Druid’s squiggles]

Epistle 3, D&D edition: reference guide

The story can be found here

Context, timing of the story

Understanding the background that lead to the story being written is not necessary, but I’ll include it. Long story short: I compared our seemingly never-coming D&D to similarly coming video game Half Life 3 (Half Life 2 episode 3). Yesterday, on the 25th of August, 2 AM local time the writer for Half Life series posted a blog post (Epistle 3), which detailed a plot for the never-coming Half Life game (archive, with names corrected). This gave us a closure, but also pretty much confirmed that a much-expected Half Life sequel isn’t coming.

Since I like to be on the bleeding edge of memes and references, I spent about 4-5 hours writing a story that would — just like Epistle3 — conclude the campaign in lieu of actual sessions.

The plan absolutely worked, as I care a whole lot less about playing D&D with that group now that the story is written. However, it’s worth noting that:

  • I still hope for further sessions. I just won’t be butthurt when my party fails to have time for a D&D session for the fifth consecutive month
  • The story as written is not what was supposed to happen in campaign.

I have toyed with the idea about making D&D into a Half Life 2 episode 3 we never got, but eventually decided against it for multiple reasons. The fact I binned the idea made it perfect for the ‘fake’ campaign ending, as I didn’t want to spoil the actual campaign for my party … if we ever get back to it 🙁

Before we go on to the rest of the references, be warned: I play too much Counter Strike: Global Offensive for my own good. Readers of my How to Train Your Dragon-based webcomic can attest to that.

Note on homebrew stuff

I think metallic dragons in D&D look retarded, so I homebrewed the “you can’t tell alignment by color in this campaign” rule (therefore: chromatic dragons aren’t unecessarily evil). This works because some of my players thought alignment is a dumb concept, so we agreed to just ignore the alignment part of D&D. Don’t judge, we’re fucking plebs, me as well but especially the players.

Notable Characters (PCs and NPCs)

The full cast of player characters comprises 5 people:

  • Gar, 25-30 year old human male. Paladin.
  • Kvothe, 16, human male. Gypsy. Bard.
  • Kalgathre Crawflower, human female, ~20. Kali for short. Mage.
  • Nerishana Bearcharger. Female elf, 20. Neri for short. Ranger.
  • Sergor Tigersoul. Male human, 22-25-something years old. Barbarian, wants to multi-class druid.

There’s also about half dozen of named NPCs:

  • Lore, the red dragon.
  • Duncan Shields (only mentioned tangentially).
  • Bogdan, the dwarf
  • Joshua Nissan, the druid
  • Gmuk, a goblin the party captured in the first few sessions


The backstory of Nerishana is referenced in the story, where the dragon is said to be helping to solve the ‘elven overpopulation problem’.

According to her backstory, she grew up in a nomadic elven tribe. The clan started to number too many, so the leader of the clan decided that each youngest (probably meant as in ‘not firstborn’) child has to leave the tribe after the rite of adulthood. They may only return once they have proven their worth in the world. (In short: if you combine the Dalish from Dragon Age: Origins and Quarians from Mass Effect, you get basically this)

In previous sessions, she started to call ‘Lore’ a ‘chicken fucker’. I don’t like that, and by extension, the dragon doesn’t like that either.


According to my notes the dragon wasn’t named — despite being a potentially major NPC, so I had to make up a name. Why not a CS:GO reference? The dragon only appears to speak draconic.

Duncan, Bogdan and Joshua Nissan

Those characters are named after/reference real people. Duncan ‘Thooorin’ Shields is a CS:GO analyst. Bogdan and Joshua ‘steel’ Nissan are two CS:GO players, who had a bit of a drama some time back. Both Bogdan and Josh were created specifically for the story.

Game background

Before the events in this letter, the party was following the road north. They spotted a mine, so they took a detour and investigated the mine. The mine led to some caverns, inside of which there was a bandit camp. Bandits didn’t like the intruders, so the situation eventually ended in a fight, which ended with party killing everyone.

Memes and references to events and obscured stuff (in the story)

Still Alive

Well, there’s plenty of excuses to be had, but there’s no sense crying over every mistake. We just keep trying until we run out of cake. The quest gets done and you bring some loot home for the chars who are still alive.

This bit references a song from video game Portal, Still Alive (fun fact: Portal games happen in the same universe as the Half Life series)

Smudged text

Smudged text is not a reference. Instead, it is only meant to avoid spoiling the next planned segment in the campaign for the party (assuming the campaign continues).

Nerishana’s end

Is what happens if her player calls Lore a ‘chicken fucker’ ever again.

Bogdan’s/Lore’s sign

‘U can’t touch this’ is a reference to a song by MC Hammer. Skrilla basically means money. The writer of the letter making a connection to Duncan is referencing Thorin (CS:GO analyst, IRL Duncan) using the phrase when thanking a website that sponsored his videos, AlphaDraft, for the money. ‘If you can read this, I’ll argue with you about anything. 1 gp / 5 min’ refers to Monty Python’s Argument Clinic.

Bogdan’s serpent longbow

Is a reference to a sniper gun in Counter Strike: Global Offensive (Dragon Lore. The gun is available in various levels of wear, with the shiniest version (Factory New) selling for just under €1600 at the time of writing.

Bogdan asking Josh to throw him his bow and arrows

This references a mini-drama that happened in CS:GO community some time ago. IRL Bogdan and steel (IRL Joshua Nissan) were playing a CS:GO match. They were on the same team. During some round, Bogdan got dropped to 1 HP, and asked steel to drop him an AWP (long-range sniper rifle), because at a single point of health, he can do more from the distance. steel, of course, didn’t want to drop him an awp. Since both players are semi-famous in the scene (and since this happened during a live stream), this exchange became a hot topic for all armchair CSGO experts on reddit and gave us the SIMPLE ISNT BOGDAN meme.

Joshua and the throwing lesson

IRL Joshua Nissan (steel) was a member of the CSGO pro team IBuyPower, which was involved in a match fixing scandal. This resulted in steel (and others) being banned from competing in Valve-sponsored CSGO events (as well as some other pro leagues).


Since Borealis would make the HL3 connection too obvious, I decided to substitute the ship for a different one. The ship was delivered by Witcher 3 (which itself took it from the Norse mythology)


Multiple things on this page reference Eminem’s song Stan (and its Middle-Eastern themed parody):

  • The first and last sentence of the last paragraph (excluding the greeting above the signatures) are modified lyrics from the last Stan’s segment of the song.
  • Same with the d20 bit in the title (the ‘it’s prohibited by religion’ bit is from the parody)
  • The description in the document’s head (picked up by some social networks when embedding) features lyrics of this song, modified to include a How to Train Your Dragon as well as a meta reference.

Why Sergor’s company

No specific reason (and by that I mean it’s not inspired by the campaign itself. In the campaign, the party isn’t even a ‘company,’ instead it’s just a group that has no reason to stick together, thus not even worthy of the name).

For the purposes of this story, this had to be a company and it had to be named, so I looked at the names I’ve had at my disposal and figured which ones are my favourites. I look at which characters aren’t weaklings. Sergor won.

The story can be found here