The best kittens, technology, and video games blog in the world.

Saturday, June 30, 2018

UK was never much of a democracy

Your Queen by garykemble from flickr (CC-NC)

The concept of "democracy" is very loaded, but let's focus on its most basic part - people vote, and whoever gets majority of votes gets to run the government for the next few years. UK fails this standard miserably.

Here's percentage of votes in Parliamentary elections received by whoever got to run the government over last hundred years. And it wasn't any better before:
  • 1918 - 38.4%
  • 1922 - 38.5%
  • 1923 - 38.0% (minority government)
  • 1924 - 46.8%
  • 1929 - 37.1% (party which "won" didn't even get plurality)
  • 1931 - 55.0%
  • 1935 - 47.8%
  • most countries continued having regular elections during wartime, but UK didn't even bother
  • 1945 - 47.7%
  • 1950 - 46.1%
  • 1951 - 48.0% (party which "won" didn't even get plurality)
  • 1955 - 49.7%
  • 1959 - 49.4%
  • 1964 - 44.1%
  • 1966 - 48.0%
  • 1970 - 46.4%
  • Feb 1974 - 37.2% (party which "won" didn't even get plurality)
  • Oct 1974 - 39.2%
  • 1979 - 43.9%
  • 1983 - 42.4%
  • 1987 - 42.2%
  • 1992 - 41.9%
  • 1997 - 43.2%
  • 2001 - 40.7%
  • 2005 - 35.2%
  • 2010 - 59.1% (coalition)
  • 2015 - 36.9%
  • 2017 - 42.4% (minority government)
So in 27 elections, there were only 2 cases where government was actually backed by majority of the votes. And usually these weren't narrow margins just a bit under 50% (like George Bush in 2000 or Donald Trump in 2016) - it's routine for parties to govern with just 35%-40% support.

In fact it's more common for a party to "win" without even getting plurality than for someone to actually get genuine democratic mandate.

There's a lot of concern about democracy fading worldwide. When you look closer, maybe there wasn't that much of it in the first place.

Wednesday, June 13, 2018

Challenges for May 2018 SecTalks London

そんな目で見ちゃダメだねぇ by amika_san from flickr (CC-ND)

Last month I ran another round of London SecTalks CTF.

There were 8 challenges as before. And again, the winner only did 7 of 8 on time, the last one (Monoalphabetic) only after the event.

Challenge files and code used to generate them available on github.

There are no answers below, but some serious hints which might make it too easy.

For previous rounds, see posts about September 2017 and November 2017 CTFs.

Invisible Flag (5 points)

It's a third iteration of the zip challenge.

There's a zip file containing 16 zip files inside. And each contains 16 more zip files. And so on for 16 levels, until you get to the flag.

For a small additional complication, the flag is completely invisible, and made out of different types of Unicode spaces. Replacing special spaces with different characters will reveal it.

Perl (10 points)

It's a very simple password validator written in very straightforward Perl.

The validator is mostly a sequence of commands like

s/^(.{7})i(.*)$/\2\1/;

Which removes character "i" from 8th position, and swaps everything before and after it. If the answer is empty, the validation is successful.

The easy way to solve it is to work backwards from an empty answer.

Almost Invisible Flag (15 points)

The challenge is an image with 1s and 0s written onto it in a very faint color. Once you figure that out, and transcribe the numbers into a binary file, it's a zip. Unpacking it reveals the flag.

React.js (20 points)

It's a react.js based validator. Validator is build of component layers, first layer checks length of the password, then each layer checks one character and passes the data to next layer with some transformations applied.

React Developer Tools for Chrome can be quite helpful for this.

This can be solved in many ways. You could brute force each layer with a simple script, or turn React code into a recursive function, and solve in an old fashioned way.

RSA (25 points)

For this challenge p and q are very close to each other. In fact they differ by just 2. There's a very simple attack for such case.

Monoalphabetic Cipher (30 points)

This challenge is a bit of text with flag embedded in it, encrypted by monoalphabetic cipher - all lower case letters, upper case letters, digits, spaces, punctuation each getting separate character.

The trick is that symbols used by the cipher are all emoji, which doesn't make the challenge any harder, just more fun.

The slight difficulty is that the text is not actually in English, so statistical methods can suffer a small detour. It's actually in German.

This was the only challenge that wasn't solved in time, but I don't think it's really that hard or time consuming.

I really like challenges about classical ciphers, but I don't want the solution to be simply copypasting it on quipquip.

PDF (35 points)

The challenge is a PDF file encrypted by a XOR key. The content is just a result of Chrome's print to PDF function. For extra challenge the flag is censored with a black bar over it, but that's very easy to workaround.

PDFs have a lot of plaintext inside, so there's a ton to work with, however it's somewhat unpredictable where that plaintext is located.

The key is three lower case English words without spaces.

A surprise extra challenge is that I accidentally left newline character at end of the key, which I only noticed during the challenge and told the contestants.

Javascript (40 points)

It's a very simple Javascript validator, obfuscated with jsfuck to only use 6 charecters.

I expected that people would need to write a simple JSFuck decoder, and that's why it's worth so many points, but most people just used Chrome debugger instead to solve this challenge really quickly.

Monday, May 28, 2018

Preconstructed Magic Decks on mtg.wtf

2018-05-28-13 by RobynAnderson from flickr (CC-NC-ND)

There's now a number of search engines for Magic cards, but some information is still missing from them all.

I just fixed one of such areas. mtg.wtf now has searchable contents of all preconstructed decks ever released. They contain cards from correct set, so viewing a decklist like this you can see actual cards which are in the deck. Every other decklist visualizer I've ever seen just gives you the most recent scans (like this for example), which looks really weird, especially for older decks.

You can view the decks, download decklists, or mix deck queries with other queries. For example to see which cards from Feline Ferocity are Modern-legal, just use deck:"Feline Ferocity" f:modern.

All this information is available in simple machine readable format.

Raw data is in magic-preconstructed-decks, and compiled jsons are in magic-search-engine repository.

Future enhancements

There's still room for improvement - information which cards are foil is missing, but easy to add. In theory it should be possible to find exact card printing instead of just set it's from (how many copies of which basic land etc.), in practice it might be a bit too much work.

Decklist visualizer could get extra features like sample hand, mana curve statistics etc.

And inevitably like with every project, there's going to be some errors. If you find any, please report them on github.

Monday, May 07, 2018

Wonder Woman review

Superkitty! by swxxii from flickr (CC-NC)

The movie is bad. Everything about it is bad. Like Star Wars prequels tier bad, but there won't even be any memes.

It's not about Wonder Woman

First of all, it's not even about Wonder Woman, it's all about her boyfriend. He's driving the whole plot, and she just tags along, without any sense of what's going on.

Diana (the "Wonder Woman") doesn't make any choices in the whole movie. The closest she gets to doing something on her own is choosing an outfit in a pointless shopping scene, and then she decides to dress up like him. Just wow.

Every time she suggests something (usually "omg, we got to help those people"), he just shuts her down, and then she does things his way.

The world makes no sense

Obviously the movie shits at actual Greek mythology.

As far as I can tell, the Amazons on the island are just some mortals. They have no children, and seem to be aging, so between ancient Greek times and World War 1, they should all be dead, right? Or is it some Star Trek time bubble? And how do they even speak English and all the other modern languages if they've been isolated from the world for who knows how long?

Then there's a framing device with pointless email from Batman. Like, what the hell? Greek Gods and Batman do not belong in the same movie in any way whatsoever. The comics tend to be stupid like that, but it served no purpose whatsoever.

And of course there are unexplained black Amazons, Hollywood has racial quotas to fill.

Action scenes are few and bad

There are three action sequences in this 2h 21min "action" movie.

Early on there's German army landing on Amazons' island, where the Amazons dance-fight, doing bows trick shot, and combo moves with spears, leashes, and such. Wearing the kind of "female armor" everyone has been making fun of for last 30 years. It's all rather silly, but probably still the best part of the movie.

Then about an hour of bad acting later there's storming of No Man's Land. Wonder Woman runs into machine gun fire, and the movie gives up on any internal logic. I couldn't tell - is she bullet proof or not? If she is, then why the hell is she tying to block bullets one by one with whatever piece of token armor is on her forearms? It's ridiculous every time she does it. And if she's not bulletproof, then how isn't she dead exactly? There's a lot of bullets out there, and she's not exactly waving her arms to block.

Anyway, leaving extent of her powers aside, somehow here mere presence makes all bullets miss everyone in the whole British army, who all decide to run after her, without anyone getting even a scratch.

Another hour of bad acting later, there's final boss fight which is basically shitty CGI, and least entertaining of all three.

The villain

Invincible superheroes are inherently rather boring, and decent superhero movies rely on an interesting villain to work. Wonder Woman's is about the worst, as the main villain gets like a minute of screen time within the first two hours before an obvious surprise plot twist reveal.

Villain's two henchmen get a bit more screen time, one of which Wonder Woman decided to kill, the other one to spare, for pretty much no reason whatsoever.

So instead the fighting is mostly against random German and occasionally Turkish conscripts who have absolutely no idea what the hell is going on around them. Then again, there's not that much fighting in the movie.

Morality

I think the movie attempts to have some moral message about violence being bad, but delivery is so ridiculously poor I'm not even sure what they've been going for. In the end, she ignores her moral intuitions and does whatever her boyfriend asks for. Is that the message perhaps? Do what your boyfriend says?

Sidekicks

At some point the boyfriend and his sidekick Diana assemble a team. None of them does anything. Some Native American "chief" sends smoke signals at some point, it's not very clear why. They try to do some fighting, but Wonder Woman does all the work anyway.

Acting

The only person who got any kind of character development is the boyfriend with his heroic sacrifice. Diana starts the movie as Wonder Woman, ends the movie as Wonder Woman, and her character development is, I guess getting her first boyfriend?

All the acting from Gal Gadot playing Wonder Woman was bad, so maybe they tried to salvage the movie by giving somewhat more tolerable Chris Pine playing the boyfriend more to do, until he took over the whole movie?

Conclusion

The movie has are no redeeming qualities. I watched it yesterday, and it's already rapidly fading in my memory other than the silly dance fight scene.

The only thing you'll achieve by watching it is convince yourself that critics (who for some reason love it) are all idiots, but you should probably know that by now.

Tuesday, March 27, 2018

Let's make Lucca Mission Pack mod for Europa Universalis 4

In this post we'll create a very simple EU4 mission pack mod. I'll use Lucca as an example. It will be more fun if you pick another country, follow along these step, while customizing your mod a bit.

This is a beginner level tutorial. It doesn't require any skills beyond use of text editors. Because we'll need nonstandard encoding support to deal with localization files, I recommend Visual Studio Code, but other than this one step pretty much any editor will do.

For some more details on how mission system works, you might want to check my previous post. To just learn the new mission system from a player's perspective, watch DDRJake's videos.

There's more to the mission system than can be covered in one tutorial, so I want to write another one covering more advanced subject later.

If you have any questions about these steps, ask them here, or reach me on any social media.

Create mod descriptor

For more complex mods it's best to keep the files somewhere safe and version-controlled, like on github, but we're starting small now so I'm going to skip this step.

Open C:\Users\(YourName)\Documents\Paradox Interactive\Europa Universalis IV\mod or equivalent.

You need to create a descriptor for your mod, for this simple mod create lucca_mission_pack.mod. For very simple mod we'll only have three lines, like this:

name = "Lucca Mission Pack"
path = "mod/lucca_mission_pack"
supported_version = 1.25

name is what's going to appear in the launcher.

path is name of the folder where we'll create mod files. Create the lucca_mission_pack folder. It's best if it has the same name as mod descriptor (except for .mod extension).

supported_version tells the game which exact version the mod supports. It's used mainly to warn the user in game launcher, that the mod didn't get updated for the next version yet.

If you're following these steps in the future, change supported_version to whatever's appropriate.

At this point you can start game launcher, and see that your mod is on the list. If it's not, something went wrong with the mod descriptor and you should check it. No point running the game yet, as the mod does nothing.

Create empty mod files

Inside C:\Users\(YourName)\Documents\Paradox Interactive\Europa Universalis IV\mod\ create lucca_mission_pack folder, inside it lucca_mission_pack\missions subfolder, and inside that lucca_mission_pack\missions\Lucca_Missions.txt file.

The name of the file doesn't matter as long as it ends in .txt and doesn't conflict with any in the game. For example if you call it Hungary_Missions.txt you'll be overwriting Hungary's missions from base game - but if you call it MudkipIsBestPokemon.txt it's just fine.

Location of the file definitely matters, so if you make mistakes the mod will not load correctly.

Planning the missions

If you take a short break from modding and run the game, you'll see that Lucca's existing missions are:
  • column 1 - empty
  • column 2 - generic military missions
  • column 3 - generic diplomatic missions
  • column 4 - generic administrative missions
  • column 5 - regional missions for European countries and HRE minors
It's going to be similar for most countries, except sometimes column 5 will be empty as well.

For a small mission pack we'll create a single mission group, and put it into column 1.

For a bigger mission pack we might replace column 5 as well, add missions on the bottom, or replace some of the generic missions.

Column choice is not just for the interface, as multiple mission groups going into same columns might replace each other.

Create a mission group

Let's open lucca_mission_pack\missions\Lucca_Missions.txt in text editor and setup a group for the missions:

lucca_mission_group = {
  slot = 1
  generic = no
  ai = yes
  potential = {
    tag = LUC
  }
  has_country_shield = yes

  # missions will go here
}

What we're setting up here:
  • in column 1 (columns are called "slots")
  • not generic. This is used as priority if multiple mission groups try to use same column.
  • also available for the AI. Usually should be yes.
  • available if your tag at campaign start is LUC (Lucca). List of tags is on the wiki, usually it's first three letters of country name.
  • that we want to display country shield in the interface. This is purely graphical, but country-specific missions usually do, so let's be consistent here.
For potential you can choose based on other criteria like religion, culture, capital location etc., but they're only checked on campaign start, or when explicitly told so by an event or decision.

In vanilla game, they only change on some nation forming decisions. If you start as Lucca and form Italy, you'll keep your original missions since Italy decision doesn't change missions. If you form France, you'll get your mission pack replaced.

Creating out first mission

Time to create the first mission. We'll start with something very simple. The goal is to build a temple  in Lucca, and as a reward you'll get 200 admin points.

Open missions files, and in the place we left for missions, add this:

lucca_temple_in_capital = {
  icon = mission_european_church
  required_missions = {  }
  trigger = {
    2980 = {
      has_building = temple
    }
  }
  effect = {
    add_adm_power = 200
  }
}

What it does:
  • it sets mission's ID to lucca_temple_in_capital. This needs to be unique, and will be used for localization.
  • it uses icon mission_european_church. This is purely graphical, and I wouldn't worry too much about the icons until you're happy with how your missions work.
  • it sets lists of required previous missions to empty
  • it sets mission completion condition (trigger) - province 2980 (Lucca) has temple. You can find list of province IDs on the wiki.
  • it sets mission reward (effect) - 200 admin power points
At this point it makes sense to launch the game, and check that everything is indeed working.

Try writing something similar for country of your choice.

Start mission chain

OK, so that worked. Let's create some more missions. We'll put them all in same file, one under the other.

For design of a mission chain to be good, they should somehow connect with each other. Here's an idea for a small chain:
  • first we want to build up our capital. As a reward we get some permanent claims on nearby lands.
  • second we want to conquer claims we got in previous mission, as a reward we get some points of multiple types
  • third, we want Lucca to rival one of the big baddies, proving that we're ready. It will require completing previous mission too, so we don't need to check it again. As reward we get 25 year +10% discipline bonus for more enjoyable fights agains our new rivals.
This covers the most common cases - checking that we conquered something, getting rewarded by permanent claims, various types of points, or temporary bonuses. As well as a few extras.

Plan a similar chain for your own country, for now using similar kinds of effects.

Make Lucca Great Again

make_lucca_great_again = {
  icon = mission_high_income
  required_missions = {  }
  trigger = {
    capital_scope = {
      development = 25
      renaissance = 100
    }
  }
  effect = {
    tuscany_area = {
      limit = {
        NOT = { is_core = ROOT }
        NOT = { owned_by = ROOT }
      }
      add_permanent_claim = ROOT
    }
  }
}

Step by step:
  • it sets mission's ID to make_lucca_great_again. We'll use it as key to localization later.
  • it sets required missions to empty
  • to succeed it requires that our capital has at least 25 development and 100% Renaissance institution.  I could have used 2980 (specifically province of Lucca) instead of capital_scope (whichever province is our capital) here. We don't expect capital to move, so in this case it doesn't matter, but both selectors have their uses.
  • as reward we go through all provinces in tuscany_area and add permanent claim to them, unless they're already owned by us or have our core. Areas are defied in map\area.txt file. You don't need to use areas, you can just list provinces separately (the syntax is however a bit different).
So we can load the game, and see that it works.

Try something similar for your country. Pick some capital growth conditions, pick a relevant area from map\area.txt (most areas correspond to a state), and try it in the game.

Luccan Tuscany

We got our claims, so we ought to follow it with a mission checking that we actually conquered what we wanted.

As reward we'll just get some points, but of course you can chain a lot of conquer this area - get claims on next area missions. Making them branch in a way that looks good in the UI is a bit more advanced topic, but just making this chain as long as you'd like should be straightforward.

luccan_tuscany = {
  icon = mission_cannons_firing
  required_missions = { make_lucca_great_again }
  provinces_to_highlight = {
    area = tuscany_area
    NOT = {
      country_or_non_sovereign_subject_holds = ROOT
    }
  }
  trigger = {
    tuscany_area = {
      type = all
      country_or_non_sovereign_subject_holds = ROOT
    }
  }
  effect = {
    add_mil_power = 200
    add_legitimacy = 10
    add_republican_tradition = 10
  }
}

Let's go through it step by step:
  • it sets mission ID to luccan_tuscany
  • it sets mission icon to mission_canonns_firing
  • it requires completion of make_lucca_great_again first. If you arrange mission chain so that next mission depends on one just above it (or one row down and then sideways), the UI will draw pretty arrows to make it clearer how missions are related. Other dependencies still work, just won't look quite as nice.
  • it sets province highlight when mission is mouseovered to all provinces in  provinces_to_highlight which are not owned by us or a (nontributary) subject
  • it sets success condition of owning all provinces in tuscany_area by us or our (nontributary) subject. In addition you still need to do make_lucca_great_again first. 
  • as a reward, we get 200 mil power points, 10 legitimacy, and 10 republican tradition. Depending on government type of the country, the tooltip will only show relevant rewards, so if Lucca is a republic, the tooltip will show "200 mil points, 10 republican tradition", since legitimacy doesn't matter.
Try something similar for your country, customizing rewards, and using the same area you used in your previous mission.

You can also chain claims in a few missions.

Lucca in the Major League

So now that our Lucca conquered Tuscany, let's give it a more ambitious goal - rivalling one of big three regional baddies. As a reward we'll give it a bonus.

lucca_in_the_major_league = {
  icon = mission_cannons_firing
  required_missions = { luccan_tuscany }
  trigger = {
    OR = {
      is_rival = FRA
      is_rival = HAB
      is_rival = TUR
    }
  }
  effect = {
    add_country_modifier = {
      name = lucca_discipline
      duration = 9125 # 25 years
    }
  }
}

Step by step:
  • it sets mission ID to lucca_in_the_major_league
  • it sets mission icon to mission_cannons_firing, I just used the same one as before but feel free to pick something more creative. In the end it's just a minor graphical embellishment.
  • it requires completing luccan_tuscany first, which in turns requires make_lucca_great_again. Because we put those missions in proper order, they'll be connected by nice arrows in the UI.
  • to succeed we need to rival France (FRA), Austria (HAB), or Ottomans (TUR). You can see that in this case tags are not quite what one might guess, presumably as a leftover from EU2 or maybe even EU1 for all I know. There's no need to check that we also did our conquests, as previous mission in the chain checks that.
  • as a reward we get lucca_discipline modifier, for 9125 days (25 years). We just need to tell the game what that means in another file.

Creating modifiers

This is not strictly mission modding, but modifiers are about the most common mission reward, so it's useful to know how to create them.

In our mod create text file lucca_mission_pack\common\static_modifiers\lucca_missions.txt, and put this inside:

lucca_discipline = {
  discipline = 0.10
}

And that's it. You can check common\static_modifiers\00_static_modifiers.txt in the game for more examples.

You can put as many modifiers in single file as you want, just create your own instead of putting edited 00_static_modifiers.txt in your mod.

How EU4 localization works

EU4 localization files use .yml extension, but it's actually custom format somewhat inspired by YAML format, not the real thing.

All localization files live in localisation folder, with files sorted by language.

Each file has header like l_english, and a list of IDs and their localized strings. All the files need to start with the non-standard UTF-8 BOM. If you create a normal text file without BOM, it will be ignored by the game.

If you want your mod to support some other languages, it should be fairly obvious which file names and header to use instead.

As a bonus annoyance, Paradox can't decide between American and British spelling inside their files. Folder name is called "localisation" in all their games, but then HoI4 uses localization_key to choose entry from it. It's very easy to get confused.

Localization

So if you followed along, you have a working mod with 4 missions for your country, or however many you created. There's just one more issue - the missions all use internal development IDs instead of human readable names and descriptions.

There's 9 things we need to edit: 4 mission names, 4 mission descriptions, and name of our modifier.

Those IDs we gave the missions, they all need to be unique, so it makes sense to prefix it by name of the country or mission pack to avoid accidental conflicts, but we can localize them any way we want.

For every mission ID_title is its name key, and ID_desc is the description key. Static modifiers's name keys are just their IDs.

What we'd like to do is create lucca_mission_pack\localisation\lucca_missions_l_english.yml and put the following code there:

l_english:
 lucca_temple_in_capital_title: "Builde Temple in Lucca"
 lucca_temple_in_capital_desc: "As all good Italians, Luccans need a place to pray."
 make_lucca_great_again_title: "Make Lucca Great Again"
 make_lucca_great_again_desc: "Our capital should be the greatest city in Italy since ancient Rome"
 luccan_tuscany: "Conquest of Tuscany"
 luccan_tuscany: "Some Florentines, I assume, are good people, but they'll still be better off under Luccan rule."
 lucca_in_the_major_league_title: "Joining the Major League"
 lucca_in_the_major_league_desc: "Show the world that Lucca is now one of the great powers by rivaling a nearby Great Power."
 lucca_discipline: "Lucca's Dispciplined Army"

The game uses single space indentation, but it's not too strict about this.

What it is extremely strict about is the BOM, so if you use Visual Studio Code, choose "UTF-8 with BOM" as encoding for your new file on the bottom bar. For other editors find appropriate instructions, but many don't support UTF-8 BOM at all.

If you don't know how to get the BOM working, one think you can try is copying existing localization file, deleting everything except the first line (which might look like one broken character followed by l_english: tag) and just replacing the rest of the file with your content.

Great Success

If everything worked, you should see something like this:


Debugging

If you see image like above, but using internal IDs instead of English text, then mod is probably file , but localization is wrong. Most common issue is UTF-8 BOM.

If you see some total mess in first column, like wrong number of missions with silly names like icon, you probably made a typo in mod files, and game .

Open C:\Users\(YourName)\Documents\Paradox Interactive\Europa Universalis IV\logs or equivalent and search for hints. errors.log might give you line number where game got confused.

If mod was in the launcher, but when you play the game you see empty first column, mod probably didn't load at all. Or it did, but your potential tag is wrong, and game doesn't think these missions are appropriate for currently selected country. Double check errors.log and list of tags.

If you don't even see the mod is mod launcher, then mod descriptor file is probably wrong or in wrong place.

Or if none of that works, just ask, but remote debugging is pretty hard. I'll have easier time answering "I want mission to do X when Y" questions than "it doesn't work, what do?" questions.

Download the mod

It's best if you followed the tutorial and wrote it on your own, but if you want to check the files, all the files are on github.

Sunday, March 25, 2018

How to mod EU4 1.25 new mission system

https://www.flickr.com/photos/limowreck666/159234606/

One thing we lost in transition to the new 1.25 mission system were missions for idea groups, so I was wondering how they could be restored.

But first, I needed to do some investigating. This post is my notes, and it's primarily meant for other modders, but it could be of some use to people who just play and are interested in shenanigans.

If you want to check it from player's perspective, DDRJake recorded a series of quick presentations for some of the countries with more interesting missions.

How the old system worked

Until 1.24 every mission had separate potential check, and it could randomly appear for every country if its circumstances matched. Tag-specific missions usually had much higher weight than generic missions, so they usually appeared "in order".

On the upside, it was no trouble whatsoever for missions to be based on your rivals, idea groups, and so on.

On the downside, it was harder for this mission system to provide much guidance to players, and sometimes the RNG was pretty weird.

How HoI4 focus trees system works

The new system is clearly inspired by HoI4 focus trees, but there are some major differences too. Focuses are sort of like missions.

In HoI4 every major country has completely hardcoded tree of focuses. Focuses never change, so starting a game you'll already see Communist and Fascist focuses, even if you won't be able to ever do both same campaign (barring some major shenanigans). 

Minor countries all have the same generic focus tree, also with multiple mutually exclusive branches.

This system allows some interesting chains (see Kaiserreich for an example), and it works OKish with the full screen UI, but in the end it's basically one huge checklist per country, with nothing shared (except by copying and pasting), and no opportunity for anything dynamic - other than by making the checklist even larger.

Constraints behind design of the 1.25 mission system

The new mission system was obviously inspired by HoI4, but they faced different constraints.

People play a lot more countries in EU4. HoI4 after a few expansions has 22 focus trees, and while this isn't enough to stop demands for more, most players would be happy enough once about 30-40 or so top countries get national ideas. The kind of people who play Bhutan or Panama are a tiny minority, and generic ideas are powerful ideas that they don't have to be interesting.

In EU4 a lot more countries are played than in HoI4. There are already 353 national idea groups (counting both unique and regional groups) for 700 or so tags. There's no way in hell devs would be able to create HoI4 style trees for that many countries in a reasonable time.

Fortunately EU4 doesn't really need that kind of complexity. So instead they created modular system which allows wide range of mission trees from completely generic to completely unique.

How 1.25 mission system works

There are 5 column-shaped slots in mission pool, conveniently labelled 1 to 5 left to right.

Missions are all in groups. Each group has designated column, potential condition, and is marked as generic or not.

Each mission within a group can have a position (row), otherwise it will take the first free row instead.

When campaign starts or the mission pool is reinitialized (on some tag switching events), every mission group is checked. Every group for which potential condition is true is added to its column.

As an exception, if a generic missions wants a slot already taken by a non-generic mission, its whole group is removed. So if there's a group of generic missions for slot 4, positions 1-5, and a single non-generic mission for slot 4 position 1, then none of those generic missions will be available. Those in slots 2 and 3 won't be affected.

You can still have generic and non-generic missions in same slot, by explicitly giving them positions 6+.

If you're mixing missions this way, load order matters, as game doesn't like putting missions above previously placed missions. That's why generic missions are loaded first (file name starts with 00_).

Also putting generic missions under non-generic missions doesn't seem to work.

You could have multiple non-generic groups in same column (with or without explicit positions), but as far as I can tell, it's not used anywhere.

Possible mission pools

These combinations are used in the game:
  • countries Paradox really didn't care about like New World minors have only generic missions in columns 2, 3, 4, positions 1-5 each, for a total of 15 missions
  • slightly more important countries like Ulm get one or more regional generic missions groups in column 5. Ulm gets two groups there - one for all Europeans, and one specifically for HRE minors.
  • secondary powers like Bavaria get all that, and also tag-specific missions in column 1
  • as a slight variant, Coptic African countries get Coptic missions in column 1, African regional missions in column 5, and generic missions in columns 2, 3, 4
  • most big countries like Castile or Muscovy still get all generic missions in columns 2, 3, 4. They also get unique missions in columns 1 and 5 - and explicitly positioned unique missions in columns 2, 3, 4, under generic missions
  • a few countries like France do that, and they also replace some of generic missions. For France columns 2 and 4 include generic missions, and unique missions on the bottom; columns 1, 3, and 5 include unique missions
  • some countries like England replace all generic missions in all 5 columns
There are a few more things we could do.

How missions pools are reset

Mission pools are only changed explicitly if decision or event uses swap_non_generic_missions = yes

It is not triggered automatically, so if your Mazovia joins HRE, it won't get missions HRE minor get.

The change is included in some tag changing decisions. More or less those for which target tag has unique missions, but the lists don't seem to match exactly (like some decisions to form Japan reset missions, others don't). It's probably a few minor bugs, I don't think they're usefully exploitable.

This means that if you form England (which includes the reset) as France you get English missions, but if you form Shan (which doesn't), you keep French missions. They'll have Shan shield on them, the shield is purely decorative.

What can be easily modded?

First, the good news. If you want to create missions in format similar to what already exists, it's very easy.

So your Trebizond Mission Pack mod, or Indonesian Minor Mission Pack mod will require no shenanigans.

For this kind of mods simply check existing files, they're very easy to understand.

What requires manual resets

Now, the bad news. Anything else will require messing with the system.

For example if you religion-specific mission packs like Coptic do, let's say Sunni Mission Pack, you could simply add them to column 1 or 5, and just accept that countries which override it (like Ottomans and Mamluks) won't get your missions.

Then you could try writing mission packs for Catholics, Protestant etc., putting missions in column 1, and you'll run into a big problem - your newly Protestant Anhalt will still keep its Catholic missions, as it started the campaign Catholic.

From testing so far it seems that triggering swap_non_generic_missions = yes is completely harmless, so if you see good event for it (on_actions - on_religion_change), you could simply stuff it there. 

For things like missions based on idea groups, there's no good place to put the trigger, so perhaps it needs a regularly triggered maintenance event which will periodically reset mission pool regardless of them being needed. You can probably live with a small delay.

You could also create a decision to manually reset the mission pool. It feels a bit awkward, but works just fine from the testing. I'm not sure how to tell AI to click it the right times, so it could be in addition to other mechanisms.

Can we have more columns?

For extra missions it would be nice to add extra columns 6+. This way we could for example add religious missions in column 6, culture specific missions in column 7, idea group missions in columns 8-10, and not worry about overlap.

With vanilla UI it doesn't display at all, and a quick look at defines and interface files don't show any obvious fix. It would be nice if someone did some testing here. I'm not seeing any obvious reason why it shouldn't work.

Dev Diary once said "The grid can be as wide and tall as you like, it will automatically expand to fit all missions" - testing shows it's false, and expansion is only rows.

Idea group missions

And finally let's get back to where we started - missions for idea groups. Let's say 2 missions per full group, which is not amazing, but it's a decent start.

If we had columns, we could just put generic missions in those extra columns, somehow reset mission pool when ideas are taken (or on some timer if that's not possible).

As far as testing goes, what actually works is this:
  • create a file with some late name like missions/ZZZ_Idea_Group_Missions.txt.
  • create some mission groups, let's say all administrative idea missions in column 2, diplomatic idea missions in column 3, and military idea missions in column 4
  • even though they'll be the most generic missions possible, you need to mark them as generic = no, so they display even if nation already has non-generic missions in given column.
  • don't make them display nation's shield, it's not necessary.
  • you need to explicitly mark position, lower than any exiting missions. Portuguese and English missions use positions up to 11, so you can start at 12 unless I missed something. Or a bit below, the only difference will be extra scrolling
  • those missions will display for every nation, and simply use checks like full_idea_group = administrative_ideas in their fulfilment criteria.
Now that the investigation is complete, the only thing to do is creating a bunch of interesting missions and uploading them as a mod.

Saturday, March 24, 2018

Realistic solutions to the Israeli-Palestinian conflict

myst and menorah (1) by isfullofcrap from flickr (CC-BY)

Eight years ago I suggested a more creative solution to the Israeli-Palestitian problem. Sadly, my advice was not followed.

The most likely scenario is that the conflict will just keep on going indefinitely. The world is full of such frozen conflicts, with more getting generated - like the recent Crimea occupation. Very rarely they get successfully resolved by either force (like Sri Lanka) or negotiations (like Northern Ireland).

It seems very unlikely that either side will be able to solve this issue by force. Israel could try expelling some number of Palestinians, but they'd just move to refugee camps elsewhere. Arab armies didn't win any major war in about a thousand years (even their Medieval caliphate was mostly ran by Turks, Circassians, and other non-Arabs), and even if they suddenly became competent, they won't be able to do much against explicit US guarantees for Israel.

So let's consider for a moment a range of negotiated solutions which could possibly work, from easiest to hardest.

"Palestinians" living in Arab states

A huge obstacle to solving the problem is the official policy of Arab states, which all agreed to not grant citizenship or any other regular legal status to people born in them who are descendants of "Palestinians". This sometimes includes people with mixed "Palestinian" and non-Palestinian Arab ancestry.

Calling these people "Palestinians" is just a political ploy. They've never seen "Palestine", and back when their ancestors lived there there was no "Palestinian" national identity - it was only in the 1970s that Pan-Arabism faded away enough for any "Palestinian" nationality to start developing.

The policy of using millions of people this way, keeping them in a legal limbo to put pressure on Israel, is definitely nasty, but even worse - so far it did absolutely nothing to achieve its goals.

So as a necessary step all "Palestinians" who were born in Egypt, Jordan, Lebanon, Syria (there's an awkward civil war here, but it will likely be over long before anything moves on Palestinian issue), Saudi Arabia, Qatar, and various Arab minor states need to be granted full citizenship or equivalent, as soon as possible.

There's no possible solution without most Arab states cooperating on this. If some of them don't, the rest pretty much need to accept large number of the "Palestinians" in. Non-Arab countries could accept some number of them (like Chile and US did), but these people already share culture, language, and (generally) religion of their country of birth. It's ridiculous to make them move to another continent because of petty politics.

This can only be done unilaterally by each Arab country, so if you want to pressure someone to do something useful to get this problem towards a solution, that's the most obvious place to start.

Gaza Strip

This is really simple. Nobody has any issues with borders or population living there. There used to be some tiny Israeli settlements in the Gaza Strip, but they're all gone since 2005.

So in the end, some Arab entity will end up running Gaza. Israel and Egypt don't really care about the details, as long as security is maintained. Unfortunately so far it's not, and not only Gaza exports rockets to Israel, it also exports Jihadists to Egypt.

Apparently such terrorism is approved by 80% of the locals. As a result of this, Gaza ended up blockaded from both Israeli and Egyptian side. It's even worse, as Gaza under Hamas is in conflict with West Bank under Palestinian Authority, so even Palestinian Authority joined the blockade. Attempts to break it failed quite miserably, and probably won't be repeated.

This foolishness could easily end if attacks stopped, which would likely result in economic blockade getting gradually lifted, and everybody moving on with their lives.

Israel can't do much about it, other than building an even bigger wall, and occasionally dropping some bombs, possibly even on someone related to the attacks.

One plausible solution would be for a third party like Egypt or Arab League or the UN to take control over security in Gaza for some time, sort of like happened in Bosnia.

Israel definitely doesn't want the job, and so far nobody else volunteered. This is something Palestinians living in Gaza could in principle fix unilaterally, but in practice it's difficult as even a fairly small group of assholes could still export rockets and Jihadists even if they didn't have majority support.

As a minimum if Gazans antagonized only one of their neighbours, not both, perhaps the blockade could be loosen up a bit.

Jerusalem

It's going to remain the capital of Israel. Short of a total military defeat, there's no way in hell Israel will abandon it into some kind of international status, or just give away to the Arabs the part which happened to be on Jordanian side of 1949 armistice line.

There's some margin for negotiations of exact borders of Jerusalem, status of Palestinians living there, arrangement for the holy sites, and so on, but it's going to remain Israeli.

Trump's unilateral recognition of reality was a small step in right direction. Other countries should do the same, so we can all move on.

Money

Whichever entity ends up running Palestine will need a lot of funding, and the US, Europe, rich Arab states, and many other foreign sources will need to provide a huge deal of it to make it economically viable.

Not every problem can be solved by throwing money at it, but it works reasonably well for rebuilding economies after destructive conflicts.

As long as conflict is ongoing, Palestinian economy can't rebuild, so foreign money spent will achieve little more than temporary humanitarian relief.

One nice thing Palestinians could do to convince foreigners to be more generous would be ending payments to terrorists and their families.

There's also issue of enormous levels of corruption, but let's focus on the easier problem for now.

West Bank

There's some disagreement, but it's actually surprisingly small.

Palestinians would like to follow something like 1949 armistice lines, with as many of the Jewish settlement being dismantled as possible. Israel would like its border to follow something like the barrier wall, including most of the major settlements, annexing about 9% of territory beyond armistice lines.

Both sides are open to some degree of land swaps, and once allegedly the negotiations even reached the point where border differences were down to 3% vs 6% of the West Bank.

Security arrangements

Israel would also like some kind of strong security guarantees, which would invariably restrict Palestinian sovereignty, at least for some time. Palestinians are understandably not terribly happy about that.

Depending on how it's all designed, such arrangements could even be in Palestinian interest. The absolutely worst outcome for the Palestinians would be getting their own state, getting overran in a civil war by some local Islamists, who start exporting terrorists and rockets in every direction, and getting occupied again. Which isn't exactly unlikely.

It's hard to talk about details, as this part has the widest range of possible outcomes.

Most of these would be temporary, and once long term peace and security is achieved, such restrictions can go away. That can still take very long time, like with Bosnia.

It's possible that both sides would be happy to involve third parties in these arrangements, but third parties are not terribly happy to volunteer.

Oh wait, that was exactly the offer

What I described above was pretty much the Israeli offer in 2000 Camp David Summit. 100% of the Gaza Strip, 92% of the West Bank, $30bln resettlement fund, and some rather awkward security arrangement, many but not all temporary.

There were still significant differences on Jerusalem's holy sites, security arrangements and other such issues, but these are really tiny relative to the whole issue.

There's space for some minor tweaks around the margins, like a bit more generous land swaps, making security arrangements temporary, and throwing more money at rebuilding Palestinian economy, but any possible negotiated solution will look roughly like this, and everyone knows it.

So how is this not solved yet?

There's just no desire for serious peace negotiations on the Arab side. Arab dictators of nearby countries don't care about Palestinians, and find it more convenient to just keep the conflict frozen.

Palestinian Authority doesn't want peace, as any kind of peace would immediately halve number of "Palestinians", with the rest getting naturalized into countries of their birth. They'd rather have fake authority over all the "refugees" than a real country.

Recent American attempts at solving the problem rightly focused on ignoring Palestinian Authority completely, and getting direct agreement between Arab countries and Israel, which then PA without any foreign support will be forced to accept.

This doesn't seem terribly likely to succeed, especially with both Trump and Netanyahu so politically weak, but it's probably the best approach.

Perhaps president Winfrey will try again, and it will look almost exactly like Bill Clinton's Camp David plan from 2000, except Palestinians will be forced to take it seriously by lack of Arab backing.

Friday, March 16, 2018

Visual Studio Code first impressions

le petit chat by FranekN from flickr (CC-NC-ND)

This is a first impressions post, so not representative of editor in any serious use. Maybe it gets a lot better, maybe it gets a lot worse.

It's very important to try a lot of technologies, even if in the end, they don't matter at all. For example zsh has about one feature (multiline copy&paste support) which properly configured bash doesn't, so it's not enough to recommend it to anyone, but I kept using it after the trial.

Research stage

I tried searching the internet to figure out what's the difference between VSCode and Atom, and nobody has any good answers. Most of them were of "I already use Atom package for that" variety, or claims about performance. Atom isn't super fast, but it got a lot better since its early days. Or maybe computers got a lot faster.

Getting started

First check - Cmd-D multiple cursor selection works. OK, I might be able to use it. Any editor without it doesn't deserve a serious look. And just in case, some quick editing shortcut check - nothing is too crazy.

Second check - how do I add it to $PATH... I thought it would be in settings, but nope. Settings page wasn't very intuitive, but it actually makes a lot of sense once I got through the unusual interface. Well, this wasn't there.

I had to google that, and there were like a million irrelevant and highly convoluted answers. It turns out that correct answer is to turn on command palette with Shift-Cmd-P, and choose "Install 'code' command in PATH". Someone please tell Stack Overflow about that, it has ridiculous answers from 2015.

By the way, that's a common problem with Stack Overflow - the best answer from a few years back might be a pretty questionable today as yesterday's problems get addressed in new versions - but the answer never gets fixed, and anybody who dares ask again will get it closed as a duplicate and banned from Stack Overflow for life or something.

Maybe there should be a way to "flag as no longer best practice" or whatever.

Switching Tabs

So I opened a toy ruby repo, typed some code, and the level of git integration was pretty sweet. Staging chunks from within editor, that's definitely a nice feature.

Then I opened a second tab, and my first impressions went from 5 stars to 3 stars. Standard tab switching shortcuts like Cmd-1 Ctrl+PageDown etc. just don't work.

All right, checking the annoyingly named Extension "Marketplace", there's "Atom Keymap", that fixed it.

RSpec runner

I normally split the big screen between iTerm2 on the left and Atom on the right, so I don't usually care for in-editor runners. But sometimes I have to code on just unconnected laptop, and then it's a bit awkward.

I've heard some rumors that VSCode is good with in-editor test runner and terminal, so I checked if there's any RSpec runner. After a few tries I found "Rails Run Specs", which works for pure Ruby project, kinda.

When I right click on spec file from the file list on left sidebar, I can run the specs. But when I try to do so from command palette it just gives me "running the contributed command failed" message.

To be fair, I haven't actually checked if Atom does it any better.

So far it seems about the same

For now VSCode looks pretty much like Atom with fewer plugins. I don't actively hate it, the way I quickly hated RubyMine, Android Studio, IntelliJ IDEA, Eclipse, and a lot of such crap which never bothered to get basic usability right and just piled features on top of a really shitty base editor.

The base of VSCode is just fine. I'm just not really seeing what's the big benefit yet, but I could see using it for a bit to maybe find some.

Saturday, March 03, 2018

Volume slider's 100% limit is a massive usability failure

Headphone Kitty by Super Formosa from flickr (CC-SA)

We live in a world where all software sucks. I'm not talking about edge cases of some rarely used functionality, or compromises made for sake of backwards compatibility, or due to greed or other external constraints - we don't even get the basics right when nothing stops us.

This one is especially egregious because it affects almost all software.

Here's the problem - volume slider only going up to whatever the software considers "100%"

100% is a lie

100% means nothing. What's meaningful in audio is relative amplitude of various segments. All those ups and downs thousands of times per second are what makes the sound.

The same sound can be played at any volume you want, and it will sound just fine.

For technical reasons audio files, and that's true for both analog and digital, can be "louder" or "quieter". Does this level mean anything? No at all. The happenstance that a certain file goes from -1000 to +1000 or from -2000 to +2000 means absolutely nothing wrt best loudness to play it at.

What happened is that software decided that 1000 corresponds to some loudness at "100% volume", 2000 corresponds to some different higher loudness, and you can't do anything about it. Oh sure, you can make it quieter, but that's all.

Software doesn't even know how that 1000 translates to in any human units. It just sends some voltages to the speakers, and lets the speakers figure it out.

This usability failure was sort of tolerable back in the desktop era, because most desktop speakers have far more power than you'd normally use, so if you normally listen at 30%, then you can just bump it to 60% if software failure sends something particularly quiet to the speakers.

Unfortunately this is not true for shitty laptop speakers or shitty portable earphones. "100%" volume, very low power, and quiet audio, and it's barely possible to hear anything. Then add a crowded train to the mix...

Hall of Shame

  • Apple - 100% guilty
  • Windows - 100% guilty
  • Android - 100% guilty
  • Youtube - guilty (they at least apply server-side audio normalization for music videos, so they're less affected, but all other content has this problem)
  • VLC - desktop version amazingly goes to 200%, but mobile version (which needs it a lot more) just as guilty anyway

Dynamic range adjustment

For a bonus related failure, there's a problem of dynamic range. Movie tend to have much louder (usually action) and much quieter (usually dialogue) parts - which is perfectly fine when watching in otherwise quiet cinema.

Unfortunately at home your choices are:
  • only watch with headphones, alone
  • adjust volume up and down a lot
  • watch it at high volume so you can actually hear the dialogue, and screw the neighbours
  • watch it at low volume so you your neighbours don't complain during action sections, and use subtitles to not miss anything in the the dialogue
  • have software which flattens dynamic range to more reasonable values
At least in this case the excuse is that this kind of adjustment is not quite as trivial as bumping the volume to 100%.

Saturday, February 24, 2018

Opal - Ruby on Javascript VM - What's still missing

Freya by CarlosDemarte from flickr (CC-NC-ND)

Javascript VMs are everywhere, and environments running them such as browsers and phones look likely to remain the dominant way for users to interact with software for very long time. This led to explosion of popularity of Javascript - the native language of that environment.

But Javascript is a dreadful language. It started a dirty hack, which just so happened to be positioned right and benefited from browsers becoming universal user interface. It can't even ever get properly fixed like let's say Python 1, due to unique backwards compatibility cost.

Fortunately just as you don't need to write Java to run on JVM, or write x86 assembly to run on x86 hardware, it should in principle be possible to run on Javascript VM without writing any Javascript.

So far it's been mostly "Javascript++" style languages like CoffeeScript, JSX, TypeScript, transpiling to older versions of JS and so on. It's not nothing, but all of them are trying to make Javascript at best barely tolerable.

So why not just write in a real language, and compile it to whatever Javascript VM wants?

Opal attempts to do just such a thing, letting you run Ruby in a browser. It's a somewhat different dialect of Ruby, most notably with immutable Strings, Symbol/String unifications, single numeric floating-point type, and a few other compromises to make it run better on Javascript VM, but it's mostly good enough.

Unfortunately I don't think it's ready for serious use just yet. Here's the top 10 things it's missing, in roughly the order of importance.

Out of the box sourcemaps

When an exception happens, the most important information is where it's coming from, and the second most important is the entire stack trace. Exception type and message are usually not terribly informative anyway. With Opal, you get none of that, just some pointer to compiled code which looks nothing like what you wrote.

It's sort of true that it's also a problem with CoffeeScript, or JSX, but with such languages you can usually figure out what's up from compiled Javascript with some practice. Opal to JS mapping is too big of a change, and lack of source maps makes debugging extremely tedious.

Opal absolutely needs sourcemaps, out of the box, in every environment. That's the single barrier to productive use.

Decent test framework

Opal has opal-rspec and it's just not good enough. It doesn't work with latest version, doesn't give any meaningful information why a test failed, doesn't have any mode other than "run all tests", and is weirdly slow on top of it all.

This isn't even all that surprising, as Javascript testing is decade behind Ruby, and sourcemap issue on top of that makes it even worse. It's a huge productivity killer.

binding.pry

One of best features of ruby is binding.pry. For that matter one of the best features of Javascript is debugger, which is basically less powerful version of binding.pry.

With Opal, you get none of that. You can use `debugger` and try to figure out things from compiled Javascript code, but that's not exactly a pleasant experience.

Support for Ruby regular expressions

Opal doesn't support Ruby regular expressions, just throws whatever you write onto JS regexp engine, and it's not even close to good enough. Even something is simple as /\A\d+\z/ will completely fail - and even worse it will fail quietly without raising an exception.

Of course you can write JS regexps, but then you lose any hope of sharing same codebase between regular Ruby and Opal Ruby.

As an absolute minimum it should raise a damn exception when it sees something it can't deal with.

Support for Time.parse

Another thing which turned out to be far more annoying than expected is dealing with timestamps. Ruby has Time.parse, which is pretty decent at handling most commonly used timestamp formats. Opal will instead happily use raw Javascript constructor, and quietly give you NaN timestamp object.

Like with previous point, the absolute minimum is to raise a damn exception here, but something resembling Ruby's Time.parse would go a long way towards making Opal useful.

pry-rescue

As followup to some previous points, something that lets you jump straight into pry on unhandled exception would be pretty damn good. Especially if it also worked in the test suite.

Precompilation of libraries for better start time

Ruby doesn't have separate compile phase - it just executes code on a fresh VM, and that code setups various methods and classes via metaprogramming. Then it runs the application itself.

That works fine on Ruby VM, but most environments perform really poorly in this mode. Startup time of Ruby on JVM with JRuby or Javascript VM with Opal is thus fairly bad.

This is probably the most difficult thing to do, but right now any Opal code using a medium-sized wrapper like opal-d3 will have a lot worse startup time than native javascript version.
Once it starts, overhead isn't too bad, but this really needs to be solved for production use.

Better interoperability with plain Javascript objects

This is another point about debugging, but let's say I get a Javascript object somewhere, and I want to figure out what the hell it is, or just dump it to the console. Currently it's going to crash with a helpful message telling me that Javascript objects don't implement inspect method. Well, true, but it's awful debugging experience, as realistically we'll be mixing Opal Ruby code with native Javascript libraries in most use cases.

A site like codepen.io

One of the nicest things about frontend coding is that it's possible to quickly code something in the browser, without going through all the hassle of setting up local environment, and share that with others. There's a lot of sites like codepen.io which help with this low-overhead quick coding.

Opal will definitely need a site like that, or be supported by one of them.

A Killer App

And finally we get to the usual "Killer App" point. I put it last intentionally - because unless most of the previous points are addressed, there's no killer app which could possibly work.

Saturday, February 17, 2018

Review of Star Trek: The Orville


It's usually not worth writing reviews of works with a lot of existing reviews. Either you agree with the consensus, and so provide very little information beyond what's already there, or you disagree, and the review probably says more about your taste than about the subject.

Lack of consensus

Not this time. There's no consensus at all. Critics absolutely hate The Orville:
While the audience loves it:
This is extremely unusual. Audiences and critics usually agree very closely.

Meanwhile, Star Trek: Discovery has far higher critics score:
and very mediocre audience score:

So what's the deal here?

It's simple, the critics are total idiots, and the audience is completely right. Star Trek: The Orville is awesome.

The review

The Orville is 90% classic Star Trek and 10% Family Guy. This combination is just too sophisticated for the stupid critics, but it works really well.

Star Trek was always a very optimistic and lighthearted world. Even its "dark" parts like DS9 would look like a comedy by standard of today's grimdark TV. Dark moments like In the Pale Moonlight were only so effective because they were used to sparingly against the backdrop of endless Ferengi get rich schemes, Odo and Quark's cat and mouse games, shenanigans by the station's kids, Kai Winn's pettiness, and so many other ways which made the future look so much brighter than world of today.

And it couldn't have worked any other way. Star Trek has to be bright for moral dilemmas to be engaging. If the whole world is a grimdark shithole, moral issues become irrelevant, and only survival matters.

The Orville continues doing what Star Trek was great at. Its universe, while technically not in Star Trek canon, is just like it - full of imperfect people still trying to be their best. They explore the universe, run into interesting aliens of the week, and seriously deal with new moral dilemmas just like in previous Star Trek series. It feels like it's actually doing a better job, with choices characters make having far more serious consequences, instead of being promptly forgotten by the next episode.

Sure, previous Star Trek series didn't employ Family Guy style humor, but 80s'/90s' sensibilities wouldn't work on today's TV, and this change is far less drastic than turning Star Trek into another grimdark series like everything else.

It's a must-watch for every Star Trek lover. It's still trying to perfect its formula, but it might very well end up as the best Star Trek series ever.

The bonus review of Star Trek: Discovery

To be fair, I only watched the first episode, but that should be quite telling as I watched every other Star Trek series and movies, many multiple times.

Discovery is simply not Star Trek. Maybe I'd have liked it if it didn't pretend to be one, but it's too late now.

It's just ridiculously grimdark. The characters, the antagonists, the plot, everything on the screen is just ridiculously dark. It hurts to even look at the screen. There's not one scene in the whole episode where the lights are properly on - it's all dark greys and blacks everywhere.

It's so ridiculously Not Star Trek that there's a damn mutiny in the first episode, by the first officer who wants to start a war with the "Klingons"!

As if that's not enough, for some reason it ditches Star Trek races - Discovery "Klingons" look and act nothing like Star Trek Klingons, there's a few Vulcans in the background, but they decided to ignore whole Star Trek Vulcan canon anyway, and there's some humans and some weird new types nobody cares for.

As far as I can tell - and maybe that changes later - it's doesn't even follow the crew ensemble formula, instead focusing hard on single character, who's a woman most annoyingly named Michael.

So why does it even call itself Star Trek? That sets up expectations it's completely unwilling to meet. Perhaps it could be a decent space show in its unique universe, instead it decided to steal the name and then do something completely unrelated with it.

There was nothing redeeming about the whole episode, and I doubt very much it gets any better later.

Just don't bother watching it.

Saturday, February 10, 2018

Let's Play XCOM: Enemy Unknown

It's time for another classic game - XCOM: Enemy Unknown!

The Long War mod would make it last about 200-300 episodes instead of more reasonable number like 40 or so, and let's be honest - there's no way in hell I'd be able to finish it. Even people with a lot more time than me left a lot of Long War let's plays incomplete.

I got a bunch of minor mods, two most interesting are:

  • Tweaking perk tree, and perk pool for training roulette. This mostly fixes Snipers by making Squadsight the first perk, and delaying Headshot until major-tier perk. It also makes Supports into reliable medics by removing medic skills from the pool.
  • Making alien line of sight a bit shorter to occasionally enable ambushes. This could probably be cheesed by the kind of people who like counting tiles, but I never felt like doing so.
The rest is largely UI. Playing on Classic difficulty, so there should be some challenge, especially since I probably forgot everything about the game by now.

The let's play is almost exclusively battles, with base management in between cut out, as you probably don't want to see me alt-tab to spreadsheet and wiki and counting how much power I need to build when and how many corpses I need to sell on grey market to get necessary space bucks for foundry upgrades.

Here's the first episode:



As usual, episodes coming out once a day, same time of the day, until we win or aliens do.

Monday, January 29, 2018

London cycle hire adventures

Lilith on bike seat by catmom42 from flickr (CC-NC-ND)
Today I felt like coming home with a cycle hire (commonly known as "Boris Bikes", officially now "Santanders Cycles" after a rebrand).

I went to a nearest dock, which the app claimed to be in perfectly fine order, and tried to get a bike. Error. Tried a few more times just in case, still error. I thought that's just app error, so I tried to use the terminal instead - which is really painful as it involves clicking same stupid confirmation dialogs about 25 times before it lets you rent the damn bike - but it was just as broken as the app.

Could the app somehow mark the dock as not working? Right...

So I walked to the next dock, that somehow wasn't broken, so I got a bike, cycled to Aldgate, and from there to the end of pompously named "Cycle Superhighway 2" at Stratford.

Stratford is a traffic hell, with no docks near the "Cycle Superhighway 2" or the station. The app claimed the nearest two docks had zero spaces left.

There was one about 10 minutes away from the station which claimed to have 4 free spaces. I went there - wasting tons of time going in circles because direct route is not possible anywhere near Stratford - and there was only one space, which didn't take the bike in spite of repeated attempts, for whichever reason. First it flashed red, then it just gave up.

After a lot of loud cursing, I had to cycle to the next dock, which fortunately somehow had free spaces, probably because it was really damn far from the station.

The cycling itself was fine, just everything else about the experience was totally miserable, and of course they charged me extra for wasting my time due to broken docking stations.

Which is pretty much what I learned to expect from the TfL. Unionized 💩💩💩.

I really hope some competition with dockless bikes comes to London. Right now none of these new schemes allow realistic commuting between Central London and zones 2/3, but there's some hope for the future.

Tuesday, January 23, 2018

Let's Play Civilization 5 as Rome

It's been a long while since I last recorded any Let's Plays, so here's a new one!

It turns out not everybody switched to Civilization 6, and in fact new mods for Civilization 5 keep coming out. This campaign features one of them - 5th Unique Component. Other mods just as before.

As Rome, our unique abilities are:

  • 25% faster production in other cities of every building which is already built in our capital
  • Ballista - unique Catapult replacement - slightly stronger
  • Legion - unique Swordsman replacement - slightly stronger, can build roads and forts
  • Forum - unique Market replacement - +10% Great Person
  • Thermae - unique Garden replacement - +1 Science, +1 Culture, +1 Food.
  • Aedes - unique Temple replacement - +1 Global Happiness, cheaper to build, costs no maintenance, and doesn't require a Shrine.
Overall these feel like mid-tier or a bit below abilities. Faster production scales with number of cities, and Aedes gives us a bit of happiness breathing room, so together they support a bit of expansion. Unique units come too early and are of wrong kind to have much impact, early wars are dominated by Composite Bowmen supported by Horsemen.

I'd definitely love to hear feedback, especially technical feedback - I'm recording at higher resolution, and I'm not totally sure if I set OBS correctly for it.


One video a day, full playlist going to be here.




Saturday, January 20, 2018

New Hash methods in Ruby 2.5 and hash-polyfill

The Cat by marcinlachowicz.com from flickr (CC-NC-ND)

Ruby 2.5 includes a bunch of new Hash methods:
  • Hash#slice
  • Hash#transform_keys
  • Hash#transform_keys!
The first two do exactly what you'd expect them - and the same ActiveSupport's methods with the same names do. In case of key conflict Hash#transform_keys will quietly overwrite keys, which is somewhat questionable behaviour, but it's not like there's obvious better way.

Unfortunately Hash#transform_keys! took some shortcuts, resulting in rather questionable behaviour. I submitted it as a bug report, and hope they fix it soon, but to be honest track record of my Open Source bug submissions is rather poor.

I'm really surprised Hash#compact wasn't included.

If you want to use these new methods in older Ruby versions, or if you want to use methods from future rubies like Hash#compact, Hash#select_values, Hash#select_keys etc., I updated hash-polyfill gem too.

I did not include Hash#transform_keys! in the gem as its unclear if it will have corrected or current questionable behaviour long term.