Thursday, April 16, 2020

Decoding the Level Passwords in Pushover

Pushover is a puzzle game about an ant pushing over dominos. I played it when I was a kid, and more recently I got a Steam copy of it from a cheap bundle of old games. I didn't really start playing this Steam copy until this week, at which point I remembered that, like many games of the time, Pushover has no save system. Each time the player reaches a new level, the game provides a password which can be used to return to that point.

As I played the first few levels, I noticed something interesting. The first four level passwords were as follows:

Level   Password
01      00512
02      01536
03      01024
04      03072

Two of the passwords being powers of two immediately caught my attention. If we convert each password to binary (using sixteen bits just because bits usually come in groups of eight), we get this:

Level   Password   Binary
01      00512      0000001000000000
02      01536      0000011000000000
03      01024      0000010000000000
04      03072      0000110000000000

Following this pattern, I expected the password for level 05 to be 0000100000000000, or 02048, but using this password brought me to level 07 instead. Going back to level 04, I played up to level 08 and found that, while there was still clearly some kind of pattern, it was a bit more complicated than I had thought. Converting the first eight level passwords to binary, we have:

Level   Password   Binary
01      00512      0000001000000000
02      01536      0000011000000000
03      01024      0000010000000000
04      03072      0000110000000000
05      03584      0000111000000000
06      02560      0000101000000000
07      02048      0000100000000000
08      06144      0001100000000000

At this point, we can already start to see what's going on, if we look at the binary in columns. There seems to be a pattern emerging:

  • The 29 bit column (10th from the right) has 2 ones, 2 zeros, 2 ones, and 2 zeros; we might expect this to continue indefinitely.
  • The 210 bit column (11th from the right), after a single zero, has 4 ones in a row, followed by some zeros; we might expect this column to have a pattern of 4 ones, 4 zeros, and so on, albeit offset by a single zero at the beginning.

However, I didn't really see it until I had played through another eight levels. Converting the first sixteen level passwords to binary, we have:

Level   Password   Binary
01      00512      0000001000000000
02      01536      0000011000000000
03      01024      0000010000000000
04      03072      0000110000000000
05      03584      0000111000000000
06      02560      0000101000000000
07      02048      0000100000000000
08      06144      0001100000000000
09      06656      0001101000000000
10      07680      0001111000000000
11      07168      0001110000000000
12      05122      0001010000000010
13      05634      0001011000000010
14      04610      0001001000000010
15      04098      0001000000000010
16      12290      0011000000000010

Focusing only on the higher-order (leftmost) bits, we can now clearly see that:

  • The 29 bit, starting at level 01, has a pattern of 2 ones, 2 zeros, and so on.
  • The 210 bit, starting at level 02, seems to have a pattern of 4 ones, 4 zeros, and so on.
  • The 211 bit, starting at level 04, has 8 ones in a row, and has presumably started a pattern of 8 ones, 8 zeros, and so on.
  • The 212 bit, starting at level 08, is all ones all the way through level 16, and may have started a pattern of 16 ones, 16 zeros, and so on.
  • The 213 bit first becomes one at level 16.

But something is also happening in the 21 bit (second from the right), where a one suddenly appears starting at level 12. This doesn't seem related to the rest of the pattern, and I think I know why.

It was after completing level 11 that the little ant protagonist found... a bag of Quavers...? (Did I mention that Pushover was sponsored by a snack food company? I've never had Quavers; apparently they're British.) On the menu screen which appears between levels, I could see after completing level 11 that a little sprite representing a bag of Quavers had been added to the bottom of the screen where there appear to be nine spaces available. So it's probably safe to assume that nine virtual bags of Quavers are pointlessly awarded throughout the game.

The fact that the 21 bit changed after level 11 suggests that some of the lower-order bits are used for tracking the bags collected, independently of the higher-order bits which indicate the level number. As an experiment, I took the password for level 12 and flipped the 21 bit to zero, resulting in 0001010000000000 or 05120. Sure enough, entering the password 05120 took me to level 12, and upon completing the level, the inter-level menu screen did not show the bag that was there when I had beaten levels 11 through 15 before. Moreover, the password it gave me for level 13 this time was 05632, which is the previously obtained level 13 password with the 21 bit flipped to zero. However, taking the level 02 password and flipping the 21 bit to one did not result in a valid password. So I cannot cheat my way into already having a bag prior to level 12, but it seems I can enter levels 12 or later without one.

If some bits are only for tracking bags collected, and if any level can be entered without any bags, then we should be able to get a complete set of level passwords just by predicting the pattern of the bits indicating level number. The passwords of levels 01 through 16 suggested that only the higher-order bits (starting with 29) encoded the level number. So at this point, I predicted that the full pattern (if it continued indefinitely) would be as follows:

  • The 29 bit will start with one at level 01 and then change every 2 levels.
  • The 210 bit will become one at level 02 and then change every 4 levels.
  • The 211 bit will become one at level 04 and then change every 8 levels.
  • The 212 bit will become one at level 08 and then change every 16 levels.
  • The 213 bit will become one at level 16 and then change every 32 levels.
  • The 214 bit will become one at level 32 and then change every 64 levels.
  • The 215 bit will become one at level 64 and then change every 128 levels.

This algorithm does predicts the values of the seven highest-order bits for the first sixteen level passwords. Unfortunately, I realized later that it's not quite correct. While looking around in the game's files for goodies, I found that the Steam version of Pushover comes with a file called PUSHCODE.TXT — which, bizarrely, contains most but not all level passwords, and seems to have been written not by the developer or publisher but by someone from a demogroup known as Tristar & Red Sector Incorporated. The file begins:

                            TRISTAR & RED SECTOR
                                              
                                  PRESENTS

                            PUSHOVER (LEVELCODES)


LEVEL 1    00512
LEVEL 2    01536
LEVEL 3    01024
...

It continues all the way through level 67:

...
LEVEL 65   17023
LEVEL 66   18047
LEVEL 67   17535

NOTE: THERE ARE MISSING A FEW CODES!!!!

TIME BANDIT/TRSI

Pushover apparently has 100 levels, so I guess the player who wrote this file gave up about two-thirds of the way through the game. However, they got far enough to show me that the 215 bit does not get flipped to one at level 64. Any number with a one in the 215 place would be at least 32768, and none of the passwords in PUSHCODE.TXT are that high!

So I wrote a few lines of Python to convert all the passwords in PUSHCODE.TXT to binary. The results are as follows:

Level   Password   Binary
01      00512      0000001000000000
02      01536      0000011000000000
03      01024      0000010000000000
04      03072      0000110000000000
05      03584      0000111000000000
06      02560      0000101000000000
07      02048      0000100000000000
08      06144      0001100000000000
09      06656      0001101000000000
10      07680      0001111000000000
11      07168      0001110000000000
12      05122      0001010000000010
13      05634      0001011000000010
14      04610      0001001000000010
15      04098      0001000000000010
16      12290      0011000000000010
17      12802      0011001000000010
18      13826      0011011000000010
19      13314      0011010000000010
20      15362      0011110000000010
21      15878      0011111000000110
22      14854      0011101000000110
23      14342      0011100000000110
24      10246      0010100000000110
25      10758      0010101000000110
26      11782      0010111000000110
27      11270      0010110000000110
28      09222      0010010000000110
29      09734      0010011000000110
30      08718      0010001000001110
31      08206      0010000000001110
32      24590      0110000000001110
33      25102      0110001000001110
34      26126      0110011000001110
35      25614      0110010000001110
36      27662      0110110000001110
37      28174      0110111000001110
38      27150      0110101000001110
39      26638      0110100000001110
40      30734      0111100000001110
41      31246      0111101000001110
42      32270      0111111000001110
43      31758      0111110000001110
44      29726      0111010000011110
45      30238      0111011000011110
46      29214      0111001000011110
47      28702      0111000000011110
48      20510      0101000000011110
49      21022      0101001000011110
50      22046      0101011000011110
51      21534      0101010000011110
52      23582      0101110000011110
53      24094      0101111000011110
54      23070      0101101000011110
55      22558      0101100000011110
56      18494      0100100000111110
57      19006      0100101000111110
58      20030      0100111000111110
59      19518      0100110000111110
60      17470      0100010000111110
61      17982      0100011000111110
62      16958      0100001000111110
63      16510      0100000001111110
64      16511      0100000001111111
65      17023      0100001001111111
66      18047      0100011001111111
67      17535      0100010001111111

This is all consistent with my predictions about bits 29 through 214, but it's the 20 bit — not the 215 bit — which gets flipped to one at level 64. So we can revise the earlier prediction:

  • The 29 bit starts with one at level 01 and then changes every 2 levels.
  • The 210 bit becomes one at level 02 and then changes every 4 levels.
  • The 211 bit becomes one at level 04 and then changes every 8 levels.
  • The 212 bit becomes one at level 08 and then changes every 16 levels.
  • The 213 bit becomes one at level 16 and then changes every 32 levels.
  • The 214 bit becomes one at level 32 and then changes every 64 levels.
  • The 20 bit becomes one at level 64 and then changes every 128 levels.

This isn't quite as elegant as what I had initially predicted, because the "level bits" are no longer contiguous, but it appears to be correct. The last rule is already unlike the others anyway, in that we would never actually see the 20 bit change from one back to zero after 128 levels because there are only 100 levels in the game. I predicted that bit to flip at a frequency of once per 128 levels to continue the power-of-two pattern. So that last rule could just be written as:

  • The 20 bit is one at level 64 and up.

The passwords in PUSHCODE.TXT also give us a hint about how bags are tracked. It seems that each one has its own dedicated bit. If we enter the level 67 password above (17535 or 0100010001111111) and then quit back to the menu screen, we see that we have the first six bags. But if we flip a few bits to get 0100010001010101, and enter the corresponding decimal password 17493, quitting back to the menu shows that we have only the second, fourth, and sixth bags.

If there are nine bags, and if each bag has its own bit, then we need nine bits to represent them all. Meanwhile, if bits 20 and 29 through 214 and are used to determine the level, then the nine bits remaining to represent bags are 21 through 28 and 215.

From another source (the description on this YouTube video), I've found that level 100 is actually a bonus level, and that its password is 44543 (or, in binary, 1010110111111111). This is is still consistent with the above rules regarding bits 29, 210, 211, 212, 213, 214, and 20; additionally, bits 21, 22, 23, 24, 25, 26, 27, 28, and 215 are all flipped to one.

By starting with the level 100 password, individually setting the 21, 22, 23, 24, 25, 26, 27, 28, and 215 bits back to zero, entering the resulting passwords to start level 100, and then quitting to the menu to see which bags are shown, I've confirmed that each of these bits corresponds to a particular bag. Interestingly, setting 215 to zero in particular, resulting in the password 11775, has the effect of making level 100 easier by revealing the special domino types which are normally hidden on this bonus level. More importantly, though, I'm pretty sure we have now fully decoded the game's level passwords.

  • The 20 bit is one at level 64 and up.
  • The 21 bit is one after the first bag is collected (level ≥ 12).
  • The 22 bit is one after the second bag is collected (level ≥ 21).
  • The 23 bit is one after the third bag is collected (level ≥ 30).
  • The 24 bit is one after the fourth bag is collected (level ≥ 44).
  • The 25 bit is one after the fifth bag is collected (level ≥ 56).
  • The 26 bit is one after the sixth bag is collected (level ≥ 63).
  • The 27 bit is one after the seventh bag is collected (level ≥ 78).
  • The 28 bit is one after the eighth bag is collected (level ≥ 89).
  • The 29 bit starts with one at level 01 and then changes every 2 levels.
  • The 210 bit becomes one at level 02 and then changes every 4 levels.
  • The 211 bit becomes one at level 04 and then changes every 8 levels.
  • The 212 bit becomes one at level 08 and then changes every 16 levels.
  • The 213 bit becomes one at level 16 and then changes every 32 levels.
  • The 214 bit becomes one at level 32 and then changes every 64 levels.
  • The 215 bit is one after the ninth bag is collected (level = 100).

The above assumes that bags are awarded for completion of levels 11, 20, 29, 43, 55, 62, 77, and 88, based on the binary representations of the first 67 passwords passwords found in PUSHCODE.TXT and of the remaining passwords found on this page. I don't feel inclined to play through the entire game to confirm it myself before publishing this post. Given that we can enter any level just by setting the "level bits" (29, 210, 211, 212, 213, 214, and 20) — without turning on any of the "bag bits" — there's actually more than enough information here to allow me to amuse myself by writing a little Python script that gives me a valid password for any level I want to play:

import sys


def get_level_bit(frequency, level):
    offset = frequency // 2
    return (level + offset) // frequency % 2


def generate_password(level):
    bits = 0
    for index in reversed(range(16)):
        bits = bits << 1
        if 9 <= index <= 14:
            bits += get_level_bit(2 ** (index - 8), level)
        if index == 0:
            bits += get_level_bit(128, level)
    return bits


if __name__ == "__main__":
    print(generate_password(int(sys.argv[1])))

Is this really useful when I could just look up the passwords on the internet? Not really. But reverse engineering the game's passwords was more fun.

Thursday, February 6, 2020

How to Cheat in Spec Ops: The Line

Why Cheat?: A Quick Review of My Experience with a Not-Completely-Awful Game


I don't usually play military first-person shooters, let alone cover-based shooters like Spec Ops: The Line. But I got it for $1.00 (along with Duke Nukem Forever and The Darkness II) from Humble 2K Bundle 2, and... it wasn't that bad, at least on the default difficulty setting. I suppose it's precisely because I don't usually play this type of game that I didn't just see Spec Ops: The Line's cover-based shooting mechanics as an inferior version of what you would find in, say, a Gears of War game. For me, it was something different, and I enjoyed it, even though it was occasionally frustrating. Having gotten to the end of my first play-through, I could see myself playing it more, and none of the achievements seemed particularly hard to unlock, so I decided to play through the game a couple more times to go for 100% completion.

It was only at the point where I had unlocked all but one of the game's achievements — the one for beating the game on the hardest difficulty setting, FUBAR — that I realized how anti-fun the game could be. So I dropped it for a while. But after a few years of seeing 49/50 on the game's achievement tracker, it began to bother me.

The thing about me and achievements is that, while I'll make some effort to unlock them if they actually happen to be fun to unlock, I don't really care a whole lot about them otherwise... except in that they annoy me when they serve as a reminder of what's almost finished. In other words, while I don't normally treat a game with achievements as a tedious "to-do" list, 98% complete is just irritating.

So eventually, I did go back to the game and try to beat FUBAR mode, thinking it just couldn't be as bad as I remembered. But it was worse than I remembered. It was an enjoyable challenge for a while, and I actually got all the way to chapter 11 out of 15, but after a certain point, I couldn't play for more than 30 minutes at a time without getting annoyed. I wasn't enjoying it anymore, and while there were occasional moments of satisfaction in which I was able to pass a checkpoint by figuring out some optimal strategy and executing it perfectly, these moments were outnumbered by all the times when having gotten through a tough fight seemed like blind luck. The game's FUBAR difficulty setting isn't just unreasonable at times; it's also where the inherent flaws in the game's design really shine.

When one isn't having fun with a game anymore, does it make sense to keep playing just for an achievement? Not really. Not when nobody else is ever going to see or care about that achievement. When a game isn't fun anymore, the rational choice is either to drop it or to make it fun. I had begun to wonder if there was a way to cheat my way through the last bit of the game, as venting my frustration by breaking the game in some amusing way might make up for what felt like a waste of time so far. Turning that 49/50 into a 50/50 (so that even my undiagnosed OCD could accept that I'm done with the game) without having to subject myself to any more of this sadistic FUBAR nonsense would be nice too.

That's when I realized that the game's configuration files, which are encrypted in the Windows version on which I did the first half of my FUBAR play-through, are human-readable plaintext in the Linux version on which I continued the game after the termination of Windows 7 support gave me the final push towards using Linux for almost everything.

How To Cheat, The Easy Way: Step One Is To Install Linux (Which You Should Do Anyway Unless You Really Love Windows 10)


Install the Linux version of the game using the Linux version of the Steam client, and go to
~/.steam/steam/steamapps/common/SpecOps_TheLine/SRGame/Config
and you'll find a bunch of .ini files — 94 of them, by my count — and a single .txt file. I haven't fully explored the contents of these configuration files, because some of them are rather large, and there are too many of them to summarize here even if I had looked at them all. However, a quick browse through a few of them suggests that they contain variables for almost all the numerical and Boolean values one might want to alter, such as: player health, health regeneration rate, enemy health, the amount of damage required to explode enemies' heads, weapon damage, amount of ammo each weapon gets from ammo boxes, et cetera.

Some files have multiple variations. For example, the files
SRPawnEasy.ini
SRPawnEasy_Coop.ini
SRPawn.ini
SRPawn_Coop.ini
SRPawnHard.ini
SRPawnHard_Coop.ini
SRPawnInsane.ini
SRPawnInsane_Coop.ini
all contain values like character health. The ones with the "Coop" suffix obviously apply to the game's cooperative multiplayer mode, while the files marked "Easy", "Hard", and "Insane" presumably apply to the the game's "Walk on the Beach", "Suicide Mission", and "FUBAR" difficulty modes, respectively. I assume the "Combat Op" difficulty (which lies between "Walk on the Beach" and "Suicide Mission") is considered the default setting, so it probably just uses the values from SRPawn.ini (or SRPawn_Coop.ini for cooperative mode). Furthermore, I assume other difficulty modes will also fall back on SRPawn.ini for values which don't appear in their specific files, as SRPawn.ini has many more lines than the other variations.

I'm making some educated guesses here, because I haven't actually tried editing each of these files individually to confirm that the effects are what we might reasonably expect based on their names and contents. However, I did try editing the file SRPawnInsane.ini with the intent of modifying FUBAR mode. I started by modifying the health values of the player character, Walker, and his two squad mates, Lugo and Adams. This is just a matter of finding the right m_defaultHealth values. There are several m_defaultHealth lines, each appearing in a separate section indicating which character's default health level is being modified. Here's a snippet of SRPawnInsane.ini:
[SRGame.YPawn_Walker]
m_defaultHealth=60.0

[SRGame.YGamePawn_Player]
m_damageModifierExecuting=0.3
m_damageModifierReviving=0.3

[SRGame.YPawn_Lugo]
m_defaultHealth=220.0

[SRGame.YPawn_Adams]
m_defaultHealth=220.0

[SRGame.YPawn_AdamsAlone]

[SRGame.YPawn_Enemy]
m_defaultHealth=155.0
m_chanceToGrantGrenadeToExecutor=0.2
m_vaporizeModifier=3.56
m_headExplodeModifier=1.52
When I found this, I vastly increased the m_defaultHealth values found under [SRGame.YPawn_Walker], [SRGame.YPawn_Lugo], and [SRGame.YPawn_Adams]. I was unsure if it would actually work, but when I started up the game and continued my FUBAR mode campaign, it was clear that the player character and his squad mates were all practically invincible. It seemed too easy but it actually worked.

There are a few other things to note in the snippet above:
  • The [SRGame.YGamePawn_Player] section has a couple of damage modifier values; based on the names, I assume these will alter the amount of damage which the player will take while performing execution moves on enemies and reviving squad mates. However, I haven't tried changing these yet, so I don't know whether they are positive or negative modifiers. Does setting them to 0.0 mean the player takes full damage or that the player takes no damage? Presumably it's one or the other. Either way, setting them to 1.0 probably does the opposite of whatever setting them to 0.0 does, because the fact that each value is currently set to 0.3 suggests that these are fractions of the normal amount of damage.
  • The [SRGame.YPawn_AdamsAlone] section in SRPawnInsane.ini is, in fact, empty. However, it's not empty in SRPawn.ini or SRPawnEasy.ini. In each of those files, this section contains another m_defaultHealth line, so it's safe to assume that we can add one here as well, if we want to. When placed in this section, m_defaultHealth probably modifies the amount of health that Adams has during a sequence in which he is separated from the player.
  • The [SRGame.YPawn_Enemy] section contains some very specific modifiers; you can probably guess what they do based on the names. The file SRPawn.ini has even more values, any of which could most likely be modified here in SRPawnInsane.ini as well. The section name might be a bit misleading, though, as it seems to pertain only to one type of enemy. There are other sections called [SRGame.YPawn_MediumEnemy], [SRGame.YPawn_EnemyMarauder], [SRGame.YPawn_EnemyElite], and so on.
I'm just trying to give you an idea of what can be done with these configuration files. As noted above, some of the .ini files are rather large, so I'm probably just scratching the surface of what can be modified here. I haven't tried making substantial modifications myself — but it looks like you could, in theory, fine-tune many aspects of the game to be exactly how you want them. If you don't like the fact that the player can take damage while reviving squad mates, change it. If you don't like the amount of health that a particular enemy has, change it. If you want enemies' heads to explode with every headshot from any weapon, you can probably make it happen. Whether anyone cares enough about this game to do any of this, however, is another matter entirely.

I only went as far as modifying the health of Walker, Lugo, and Adams — adding a few zeroes to each number, before the decimal of course — and the rest of the FUBAR campaign was a hilarious joke. I got to the end in a tiny fraction of the time it would have taken if I had played the game fairly, and it's probably the only way I would have been willing to get to the end, as my patience had run out. And, for the record, this did unlock the achievement for finishing the game on FUBAR difficulty. Modifying these configuration files does not disable achievements.

Therefore, those of you who actually take achievements seriously as an indicator of your skill level, or something, might want to avoid playing with these configuration files while doing anything which might unlock an achievement. Personally, as noted above, I don't really care — but I can understand how others might regret unlocking a tough achievement by cheating. If you're the kind of person who takes pride in achievements, unlocking one by modifying the game might leave a bad taste in your mouth.

The Case For More Games Being This Easy To Exploit


The encrypted configuration files used by the Windows version of the game actually can be decrypted, but I can't personally vouch for the tool used to do so. I didn't bother with it when I played the Windows version of the game, because I didn't want to cheat at this game badly enough to put up with the extra steps, let alone the mysterious executable. (I trust it a bit more now that I've found it on PC Gaming Wiki, but when I first became aware of the decryption tool, it was through a link on some random forum.)

The fact that the files are not encrypted in the Linux version of the game is probably an oversight — or maybe they just didn't care, or maybe they figured Linux users would find out how to break into the files anyway, or maybe they already knew about the decryption tool for the Windows version by the time they made the Linux version so they decided decryption was pointless. In any case, the fact that the files are encrypted in the Windows version is a clear indication that players were not meant to mess with these files.

But why not?

Cheating in multiplayer games is not okay, because it spoils the experience for other players, hence the existence of anti-cheat measures in multiplayer games. When it comes to single-player games, though, I don't see why we shouldn't be able to do whatever we want with a game that we bought. Many single-player games are made to be (or just are) easily modifiable; Skyrim, for example, is famous for community-made mods. Other single-player games, however, are made to be (or just are) very difficult to modify, as the Windows version of Spec Ops: The Line would be if nobody had figured out how to decrypt its files.

It's almost a shame that a game like Spec Ops: The Line, which is considered by many to be thoroughly mediocre, happens to be one of the games in which so much of the configuration is exposed to players through plaintext or easily decrypted files. A lot of games expose graphical settings not found in-game via configuration files, but in my experience, the ability to change the gameplay this way is rare. I wish I could so easily make similar modifications to games like Alan Wake, not because they're hard and I need to cheat, but because it would be fun. I'd actually like to make Alan Wake harder. Unfortunately, it's not an easily modifiable game.

Achievements are a possible reason that a game's developers might not want players to have unmitigated access to configuration values like player health. Some people take achievements seriously, especially rare achievements which are difficult to unlock; the perceived value of such an achievement, for players able to unlock it through skill and perseverance, is lessened when someone like me unapologetically cheats to unlock it by modifying configuration values.

But just as developers can program a game to disable achievements when built-in cheat codes are activated, they could also program a game to disable achievements when some deliberately exposed configuration file differs from the intended defaults, as verified by a checksum or whatever. I guess I'm advocating for games to offer the same level of easy modification as Spec Ops: The Line, if not more, but on purpose instead of by accident.

Some developers release powerful tools for modding their games, which is great. Changing a configuration file is also great, though, especially for players who aren't going to bother learning how to use whatever modding tools exist. My philosophy as a software developer is that hard-coding arbitrary numbers is bad and everything which reasonably could be configurable should be configurable, and maybe that's far easier said than done when it comes to games — I'm a software developer, not a game developer — but I have a feeling that most games hide configuration from players on purpose, and doing this just to prevent a human from cheating against a computer is silly. The ability to cheat is not going to ruin a game for anyone with any self-control.

I'm also a big fan of games having plaintext save files, for similar reasons. I've played a few, and although I've rarely bothered to skip ahead or otherwise cheat by editing their save files, knowing that I had the option was nice. Save editing is probably hard to detect, so I don't expect it from games whose developers want achievements to mean something — but as with all forms of unintended cheating, my selfish take on the subject is that I should be able to cheat to unlock achievements, and also, deal with it.

Sorry for making the global achievement statistics for Spec Ops: The Line slightly less accurate though, I guess.

Saturday, November 2, 2019

Steam Library Update: A Quick Review

The big Steam Library update is out. I had tried it during the open beta phase, and while I was somewhat impressed by the new look, there were some things I had hoped they would improve. Maybe the performance is a bit better, but unfortunately, everything else appears to be the same.

A comparison of the old (top) and new (bottom) library designs.

At the end of the day, the library is just a fancy game launcher, whose primary purpose for those who don't use Steam as a social networking site is simply to provide a "play" button for each game, so I'm not mad enough to write a huge essay about it. I'll just break it down into lists of "pros" and "cons" and call it a day.

Pros


Aesthetics


Overall, it's more modern-looking and — subjectively, of course — prettier. At least, some aspects of it are prettier. Maybe this is too subjective to list as a definite "pro".

Dynamic Collections


The one functional upgrade that actually got me excited was the addition of dynamic collections, in addition to normal collections (previously known as categories). Whereas regular collections are static, and are defined by adding games manually, dynamic collections are based on a selection of filters, or on user-generated store tags, and thus will grow automatically as new games are added to the library. This is really nice if you want a collection for all your single-player games, for example, but don't want to keep updating it.

The filters currently available for dynamic collections.

I should note that the list of pre-defined filters available for dynamic collections is somewhat lacking (by which I mean it's only a subset of the pre-defined filters available in a store search). Oddly, I can't even make a dynamic collection for games supporting Remote Play Together, a new feature which one would assume Valve should want to promote in this way. Granted, that feature is still in beta, so perhaps I shouldn't hope for a specific Remote Play Together filter in the library yet (although there is a Remote Play Together filter in the store search). However, it should be noted that the games supporting Remote Play Together are, in theory, those with any kind of local multiplayer, and there are no built-in library filters for local multiplayer, local co-op, or shared/split screen either.

Update (November 21, 2019): Remote Play Together is officially released as of yesterday, and — as if to respond to my inane nitpicking — a "Remote Play Together" option has been added to the list of built-in filters available for dynamic collections. No other new filters have been added, though, and I still wish there were at least as many as are available in a Steam store search. I assume these library filters are the same as the store filters, under the hood.

I had hoped that the "store tags" option would make up for any shortcomings in the list of pre-defined dynamic collection filters, but a quick test indicates that this is apparently not the case. As of the time of this post, a store search for the "Local Co-Op" tag returns far fewer results than a store search using the built-in "Local Co-Op" filter. Even when the latter search is narrowed by adding the "Games" filter (thereby excluding DLC, etc.), it still returns many more results than the "Local Co-Op" tag search. It seems that store tags related to features are not applied to all products which contain those features according to the built-in filters. For this reason, I don't trust a dynamic collection defined with the "Local Co-Op" tag to contain all of my local co-op games. But I can't really call this a downside of the library update, because the old library didn't have dynamic collections at all, and the fact that the Steam store provides two conflicting ways of searching for the same thing is a weird problem which predates this update.

Update (November 21, 2019): I'm not sure when this changed — perhaps it was when Remote Play Together came out of beta yesterday — but the store's built-in "Local Co-op" filter has been renamed to "Shared/Split Screen Co-op" and thus the above example of the difference between tags and built-in filters makes a bit less sense. For what it's worth, the new "Shared/Split Screen Co-op" filter is the same as the old "Local Co-op" filter, judging by the URLs, but the name no longer matches that of the "Local Co-Op" tag, so it's harder to show that Steam is doing something nonsensical here. So I'll revise my example with filters which have not been unexpectedly renamed: Compare the search results of the "Co-op" tag to the search results of the built-in "Co-op" filter; the latter yields more results. The same is true when comparing the "Online Co-Op" tag to the built-in "Online Co-op" filter; the latter yields more results. I still take this as evidence that tags are unreliable. But again, I've gone off on a tangent regarding things which aren't strictly related to the library update, which didn't introduce this problem but merely drew my attention to it. So, moving on...

Drag-and-Drop Collection Editing


I do like the fact that I can drag and drop games into collections. Games can also be added to collections by right-clicking on them and selecting a collection from a list, which is approximately how games were added to categories before, so the new feature doesn't come with any significant loss in functionality.

My only complaint about collection editing is that adding a game to multiple collections at once is slightly more arduous than before. In the old Steam library, the list of categories was actually a checklist from which multiple categories could be selected at once. Adding a game to multiple collections simultaneously doesn't seem possible with the new Steam library. Whether you drag-and-drop or right-click, games must be added to collections one-at-a-time. However, I think it's rare that anyone would want to add a single game to so many collections that this would become too much of a hassle. What's more important is the ability to add multiple games to a single category in bulk, and this can still be done just as easily as before.

Cons


Proton Ambiguity (See Update Below)


On Linux, the library no longer indicates whether a game will run natively on Linux, or with a specific Proton version selected by Valve testing or by the user, or with the default Proton version selected for all other games. This sounds like a weird complaint, but not being able to see whether a game will be executed with Proton can be a bit of a problem.

During the recent Halloween sale, I bought a game called Oniken; the game's store page does not indicate that it natively supports Linux, but the overall rating on its ProtonDB page indicates that it works perfectly, out of the box, with Proton. So naturally I tried playing it on Linux, where I have Steam Play enabled for all games. It didn't work. A closer look at the ProtonDB page revealed that, although the game has no native Linux support, it apparently does have some kind of built-in Wine wrapper which, of course, doesn't work. I had assumed the game was running with Proton but, unbeknownst to me, it was doing something else by default instead. When I tried forcing the game to run with Proton, it did indeed work perfectly. Situations like this were a lot less confusing back when the Steam library displayed a Proton version, if applicable, next to the "Play" button of each game.

As before the big update, the built-in filter for games which run on Linux is useless when Steam Play is enabled for all titles (which is the only correct way to use Steam on Linux given the success rate of Proton in getting Windows games to work); with this Steam Play option enabled, the filter includes all games, so it doesn't actually do anything. Given that the library no longer indicates how each game will run, it would be nice if there were separate filters (or the ability to define separate dynamic collections) for native Linux games and Proton-enabled games, at least. Unfortunately, I can't find any such option.

Given how incredibly great Steam has been for playing games on Linux, this relatively minor downgrade is a disappointment, as it gives the impression (though perhaps I'm being paranoid) that Valve is losing interest in maintaining Steam as a Linux gaming platform.

Update (November 9, 2019): A few days ago, I did some digging and found a related issue report on the "Steam for Linux" GitHub page. I had no expectation that it would be fixed any time soon, but I was glad to know I wasn't the only one who noticed this glaring problem. Today, however, a new comment on the issue report claimed that the missing feature had been restored. A screenshot on a later comment shows that, sure enough, a Proton version number can be seen after clicking a game's "Show more details" button. It seems this fix is in beta, as I had to opt in to beta updates to see it, but I assume it will be rolled out to a stable release soon enough.

Grid View Dimensions


An example of the box art problem.
The new grid view uses box-art-style (portrait-oriented) image dimensions. Many older games don't have suitable images, so the banner-style (landscape-oriented) images are used and the empty space is filled with an ugly blur effect. There's no option to go back to the old grid view despite literally all games having images with the right dimensions for it.

As before the update, users can manually select custom images for games. Finding such images isn't hard; there's a site called SteamGridDB dedicated in part to providing custom box art of the proper dimensions. The use of custom box art images, where developers have not provided official images in the new format, is one way to get a uniform-looking library. However, I have nearly 800 games on Steam, and the size of my library is largely due to the fact that so many of my games were bought for pennies because they are old and/or obscure, and these are exactly the kinds of games which are more likely to be missing the new box-art style images. The use of custom images is a good solution for users with small libraries, but I have too many games which are lacking proper box-art images, and I just can't be bothered to spend time fixing it. I'd much rather be given the option to use the old grid view.

Awkward Columns


When a game is selected and Steam displays game details, the wider left-side column is reserved for friend activity, developer updates, and community content; meanwhile, the narrower right-side column has information like achievements, Steam Workshop, screenshots, DLC, trading cards, etc. If the auto-loading of community junk is disabled in the settings (as I think it should be) and there are recent developer updates or friend activity, it leaves a big empty space pushing all of the other information to the side. Some of my games have two or more screen lengths worth of content in the narrow column, and nothing in the wide column when I have auto-loading community stuff disabled. It makes sense for most content to be put into the narrow column when the wide column was designed for infinitely scrolling auto-loading content, but I think infinitely scrolling auto-loading content is annoying, so of course I'm going to disable it. Once the wide column's (annoying) main purpose is disabled, it negates a lot of the effort that went into making this design aesthetically pleasing.

Manual Links Removed (Yes, I'm Nitpicking)


The library no longer contains direct links to game manuals, forcing users to go to a game's store page or open its properties window.

Performance


Unsurprisingly, performance is poorer. With the prettier interface comes greater resource usage.

And Of Course, Bugs


There are still some bugs, indicating that the update should have stayed in beta for longer. For example, when I switch back to the Library tab from the Store or Community tabs, some parts of the library don't appear until I move the mouse over them. I've seen this on Windows 7, at least. Maybe it's just me, but I doubt it.

Sunday, August 25, 2019

Adventures in Linux Gaming

Last month I wrote about Playnite and GOG Galaxy 2.0. What I forgot to mention is that, for me personally, the major downside of each is the lack of Linux support.

I've been using Windows 7 for a long time. I didn't like the look of Windows 8 when it came out, and never saw the point in switching. Having used Windows 10 at work, I definitely have no interest in using it on my home PC, regardless of all the spying it supposedly does. I just don't enjoy using it. I suppose I don't particularly enjoy using Windows 7 either; I've had my share of problems with it. It just happens to be the best version of Windows which is still officially supported. Unfortunately, with that support ending at the start of next year, I would be forced to "upgrade" to a worse version of Windows if I want to continue to get security updates.

Do I really need security updates? I don't know. Is Windows 10 really worse or am I just biased? I guess it's a little of both. Ultimately, though, it probably doesn't matter. I've been somewhat unhappy with Windows in general, and... well, Linux is free.

Switching to Linux, and Why You Should, Maybe


Switching to Linux is seen by some as a daunting task, and perhaps there's good reason for those with no experience with Linux to be just a bit intimidated. To those terrified Linux beginners, I would recommend a user-friendly distribution like Linux Mint. That's what I'm using, despite several years of experience with Linux as a software engineer. It's just incredibly convenient. The Cinnamon desktop environment is fairly Windows-like, and Linux Mint comes with nearly all the features you need in order to avoid ever touching the command line if you don't want to. The installer is also very easy to use. Some casual PC users might not know what all of the options mean, but for those users, I think the defaults are probably fine.

Of course, no matter how automated the installer and how fully-featured the desktop environment, every Linux user will inevitably run into some kind of problem. The very same is true on Windows; the difference is that, when you search the internet for a solution to a problem on Windows, you'll almost certainly find a solution posted by someone who uses the same version of Windows. There are many Linux distributions, though; if you're not using one of the popular ones, you might find solutions which aren't quite what you need, or you might not even find any reliable documentation of the exact problem you're experiencing.

When I turn to the internet for help with installing something or fixing some error on Linux, the solutions I find are usually tailored to Ubuntu, which is fine because Linux Mint is based on Ubuntu, but it's not always the case. Sometimes the answers I find are all about Debian or Fedora. Sometimes it doesn't matter. Other times it does. I'm not saying that troubleshooting on Linux is a nightmare. These days, it really isn't. However, the fact that there isn't just one Linux comes with some inherent problems, such as this one, and troubleshooting does require a bit more patience.

But the fact that there are so many distributions means that, if you hit a roadblock and absolutely nothing works, you could always just try a different distribution.

How I Ended Up with Linux Mint


When I first decided to install Linux on my home computer, I tried Ubuntu. The installation process was mostly easy. I had some difficulty setting up dual-boot with Windows 7, but it wasn't Ubuntu's fault. It was because, while attempting to install Ubuntu from a USB stick, and I had inadvertently booted to my USB stick in UEFI mode while my Windows installation was using legacy BIOS. If you don't know what that means, don't feel bad; neither did I.

The short version of this story is that, when I booted my USB stick in legacy BIOS mode, the installation and dual-boot set-up went smoothly. However, I found Ubuntu's default desktop environment difficult to customize and annoying to use in general. Even after a bit of research, I couldn't figure out if my problems were the result of bugs or just obtuse design. Ultimately, for this reason and others, I decided that Ubuntu just wasn't for me.

That's when I tried installing Debian. The installation process seemed to work perfectly. Then I tried to boot to Debian, and nothing happened. I got a black screen. I did some research but there was really no way for me to try any of the solutions proposed to others who had similar problems, because I didn't even have a working terminal. I couldn't enter any commands. I assume that it was a video driver issue, and I could have attempted to fix it, but I decided that it wasn't worth my time. I had heard good things about Linux Mint, and I hadn't tried it yet, so I dropped Debian like a hot turd and started downloading Linux Mint.

That turned out to be the right decision; Linux Mint was easy to install, it booted up just fine, and to this day I've had no significant problems with it... except when trying to run games that were never meant to run on Linux.

Gaming On Linux


It always takes me a while to get to the point.

Linux Mint is great as a general-use desktop operating system. It comes with Firefox, LibreOffice, a media player, etc. But how is it for playing video games? Well, I'd say it's just as good for games as any other Linux distribution, and gaming on Linux today is better than ever, thanks in part to Steam.

Steam Play and Proton


A Linux version of the Steam client has been available since 2013, allowing Steam users to play any games which happened to have official Linux versions. It was only about a year ago, however, that Steam rolled out an update to the cross-platform Steam Play feature, allowing Windows games to be installed using the Linux client and providing a Wine-based compatibility tool called Proton which allows many of those games to run on Linux with very little effort from the user.

Installing Steam on Linux Mint doesn't require any command line usage, nor does it even require a web browser. You just open the Software Manager, search for Steam, select the first result, and click the install button. Meanwhile, enabling Steam Play for all games is just a matter of checking a box in the Steam settings menu. If I remember correctly, this option is disabled by default, and initially Steam Play is enabled only for officially supported games, which is no surprise; it's sensible for anything that isn't guaranteed to work to be disabled by default. But the option isn't hard to find, and often no effort is required to get games to work even if they're not officially supported.

ProtonDB tracks how well Steam games work with Proton by aggregating user-submitted reports. Games without native Linux support are rated on a scale of Borked (meaning it won't run at all) to Platinum (meaning it runs perfectly out-of-the-box), with three ratings (Bronze, Silver, and Gold) in between. I'll let the statistics on ProtonDB speak for themselves, but they appear to indicate that the majority of games are playable.

My own personal experience with running Steam games on Linux has been better than expected. Of course, I've been using ProtonDB as a resource since the beginning, and I haven't bothered to install games which are definitively rated Borked. In general, I've gravitated more toward the games with higher ratings. Therefore, I can't claim that the games I've tried playing on Linux via Proton, of which there are about a dozen, are a random sample. However, even when I've tried to play games rated Bronze or Silver, I've been mostly successful, as I've found solutions in ProtonDB's comments to some of the minor problems I've encountered. And the only game rated Borked which I've really gotten the urge to play since installing Linux Mint is L.A. Noire, and for such games, I still have Windows 7 installed on my other hard drive.

I won't describe my experience with every game in detail, but the first Windows-only game I played on Linux Mint was Max Payne, and... frankly, it just worked. It worked perfectly, actually. The only difficulty I had was not with the game itself but rather with the unofficial widescreen patch, and it was only a momentary setback. The comments on ProtonDB quickly set me straight; I added WINEDLLOVERRIDES="d3d8=n,b" %command% to the game's launch options in Steam and even the widescreen patch worked perfectly.

Similarly, Max Payne 2 works perfectly in Linux, and getting the unofficial widescreen patch to work simply requires adding WINEDLLOVERRIDES="d3d9=n,b" %command% to the game's launch options. Playing Max Payne 3 was a bit more difficult; initially, it wouldn't launch. Following the advice of comments on ProtonDB, I added PROTON_USE_WINED3D11=1 %command% to the game's launch options, and it worked, but with some bugs. The minor issues with Max Payne 3 which remain can probably be fixed, perhaps by trying one of the other Proton versions offered by Steam or by further modifying the runtime configuration, but I had only installed it for testing purposes anyway. I was really more interested in playing the first two games in the series, so I didn't spend much time troubleshooting the third.

Non-Steam Games and Wine


Despite needing the occasional web search to find the correct configuration with which to run a certain game, Steam Play with Proton is actually so convenient it's easier than ever for me to ignore the games I bought from other online stores such as GOG. While there are games on GOG with official Linux support, the GOG Galaxy client does not have a Linux version (despite a lot of GOG users wanting one). Downloading games directly from the GOG web site isn't hard, but clients such as Steam and Galaxy do offer a lot of convenience.

Furthermore, although I could probably use Wine or other tools to play many of the Windows-only games from my GOG account on Linux, it would require more effort than running Windows games via Steam, which very often just works automatically. I did install Wine with the intention of playing non-Steam Windows games, but I just haven't used it yet, because Proton — when it works, which it usually does — is just so effortless. If I'm trying to decide what to play, and I've narrowed down my choices to one GOG game and one Steam game, I'm likely to pick whichever is easiest to run on Linux, and that's going to be the Steam game nine times out of ten.

That might change a bit when I get around to trying Lutris, a game client not associated with any particular store, which also claims to reduce installation of many Windows games on Linux to a zero-effort, one click process. It looks like a promising solution for playing some of my GOG games on Linux. For what it's worth, though, installing Lutris is one extra step. I'm going to have to be a jerk and say that Steam still makes it easier by having Proton integration built in to its own client. So many of my games were already working on Linux as soon as I installed Steam that I haven't taken the time to use much of anything else.

So I don't have much to say about running Windows games with Wine, via Lutris or otherwise. I plan on experimenting with it eventually, and once I've done so, I'll probably write a sequel to this post. Right now, though, I'm looking at a huge Steam library and a high success rate with using Proton with very little tweaking, so I probably won't be straying away from Steam very often, except for the sake of experimentation. When I just want to play a game, Proton is often the best way to make it happen.

The Classics


There is one category of games for which I've already strayed outside the Steam bubble: Old-school shooters. I've got to have them.

The Steam versions of The Ultimate DOOM, DOOM II: Hell on Earth, Final DOOM, Heretic, HeXen: Beyond Heretic, and HeXen: Deathkings of the Dark Citadel all run in Proton. They were all, in fact, officially tested by Valve with specific versions of Proton, so that they show up in my Steam library with labels like "Proton [version number] selected by Valve testing" and will run with the indicated Proton version instead of the default I selected in the global Steam settings.

I find this rather amusing because the Steam versions of these games run through DOSBox which, if I'm not mistaken, has a Linux version. However, I'm not suprised that the game's publisher, id Software, hasn't made the effort to repackage these old games with the Linux version of DOSBox for an official Linux release on Steam, especially given that most users who are computer-savvy enough to use Linux will just take the game files downloaded via Steam and run them in a source port instead of DOSBox anyway.

That's what I did with all of these games, immediately after installing them. There's a Linux version of GZDoom, which isn't a suitable source port for anyone who wants the games to run exactly as they did in the '90s, but it's good enough for me. Like any sane person, I did disable major gameplay options which were not in the original games (such as vertical freelook in the DOOM games, jumping in DOOM and Heretic, and ridiculous stuff like crouching), but the graphical upgrades don't bother me.

Getting GZDoom to launch with the correct options for each game was a bit of a hassle, but no more than it was on Windows. The only real problem is that GZDoom, on my system, encounters some kind of error when I close it, which might have something to do with the fact that it doesn't seem to save changes to the gzdoom.ini file unless I enter the writeini console command while running GZDoom. Knowing the workaround, I'm not really bothered by it.

Satisfied with the DOOM and Heretic/HeXen games, I moved on to Wolfenstein 3D and its expansion Spear of Destiny, and installed the source port ECWolf. To my surprise, it seems to work perfectly despite being, in my estimation, less widely used than GZDoom. So then I moved on to the Marathon trilogy, available as freeware since 2005, and attempted to install the source port, Aleph One. That, unfortunately, could have gone more smoothly.

Not Everything is User-Friendly


The official Aleph One web site has some pretty basic instructions for installing the Linux version: Unpack the .tar.bz2 file and, in the unpacked directory, run ./configure && make && make install. Unpacking the file was easy, but I started having problems as soon as I ran the configure command. I won't bother going into all of the messy details, but I went through several iterations of trying the installation, which would fail due to missing dependencies, and then installing those dependencies.

Synaptic Package Manager, included in Linux Mint, makes finding and installing missing packages about as easy as it can be; doing it on the command line using apt or apt-get isn't very hard either. But I had never needed to hunt down dependencies like this. When installing software through Linux Mint's Software Manager, or even when installing a program using apt install, all dependencies are installed automatically (which I now regard as a miracle). Installing software manually, however, isn't quite so easy. Perhaps I was to blame for not knowing what all of the dependencies were beforehand, but it was getting frustrating.

When I finally got Aleph One installed, I was able to launch Marathon, but it printed some errors to the screen and there was no HUD. Searching the internet for a solution, it turned out I was still missing some "optional" dependencies, and installing those made things worse; my next attempt at installing Aleph One failed outright, seemingly due to a dependency which I had already installed.

That's when a comment on the Aleph One GitHub repository, posted only eight minutes before I saw it, clued me in to the fact that I had gone down the wrong rabbit hole. The easier and more reliable way to install Aleph One is to clone the Git repo, go into the root level folder, and run ./autogen.sh followed by make and make install. I had to install git (which I've used extensively but not at home) and I was still missing a couple of dependencies required by the autogen.sh script, but it told me exactly what the dependencies were, so installing them was just a matter of running the correct sudo apt install command.

So I've got Marathon and its sequels working on Linux now, but installing Aleph One took more than an hour after all was said and done. I've learned a lot, though, and ultimately the solution to every problem was revealed with a simple internet search. This story could scare people away from trying to play games on Linux, but it's important to keep in mind that I had this much trouble only because I was trying to play a 25-year-old game. Doing that on Windows isn't always easy either.

I still haven't installed the classic Quake games, and I think those are next. I can only hope installing their source ports will be a bit easier.

Conclusion


I guess the moral of this story is that installing and running games on Linux can take a bit of patience, but I only came close to running out of patience when I tried to do things that only an old-school game enthusiast determined to use Linux at all costs would ever try to do. With Steam, many of the games that work on Linux will "just work" and, for non-Steam games, I'm told that Wine isn't very hard to use either. However, I do know just enough about Wine to know that it requires some effort. The average consumer expects things to work with a single mouse click. They want one-click install and one-click launch of every game.

For games with native Linux support, you can have that. For the rest, Steam comes pretty close to providing that level of convenience. Until other stores like GOG implement some kind of compatibility layer like Proton into their own clients, Steam will dominate Linux gaming for the same reason that Windows dominates gaming in general: It's just easier.