Welcome to our guide for Linux users on how to complete the Bulletstorm achievement in POSTAL. While Linux users may not have access to Windows-only programs like AutoHotkey, we will provide a detailed explanation of the slightly more complicated process to achieve a similar result. Let’s get started!
Forewarning
This guide is written from the perspective of a Manjaro user. If you do not remember the command for your Linux distribution’s built-in package manager, now would be a good time to do so. Here’s a small refresher on these from the most popular distros:
- Arch: pacman -S [pkg]
- Debian: apt-get install [pkg]
- Fedora: dnf install [pkg]
- FreeBSD: pkg install [pkg]
- OpenSUSE: zypper install [pkg]
Of course, these also apply to distributions that are based on the ones listed here. For example, Manjaro is based on Arch, Mint is based on Ubuntu, and Ubuntu is based on Debian.
Using this guide will also grant you the achievement “Sissy” if you haven’t already. This is because of the utilization of the cheat code “gimmedat” to replenish ammunition, which is crucial to the automation of this achievement.
For the fastest completion of this achievement, the script will use the spray cannon due to its fast fire rate (completing 100 shells in about 10.25 seconds) and the 7 bullets it shoots per shotgun shell, which gives the weapon a fire rate of 4098 rounds per minute. To complete the full one million of the achievement, it would take just above four hours to completely idle this.
Installing the tool
The tool itself simulates keyboard and mouse inputs, perfect for idling this achievement to death. xdotool is likely already included in your built-in package manager, so for me on Manjaro, an Arch-based distro, this is the command to install it:
Of course, this depends on your distribution. Refer to the short list in the forewarning or your distro’s manual.
Gathering data
First, you need to know how many full backpacks of the spray cannon (which I’ll hereby call “cycles”) will be needed to complete the achievement. Find your profile’s achievement page for POSTAL (link will take you to your profile; append /stats/POSTAL to the link for your achievement progress) and subtract your current progress in Bulletstorm from one million (1000000). Given that each shell shoots 7 bullets, this means 700 bullets per cycle. Divide your uncompleted progress by 700 and round the calculation up to the nearest one, and this will give how many cycles you need to complete the achievement. Note this down somewhere, whether it be physically or not.
Next, xdotool should know the window ID of POSTAL (for the sake of refocusing the game when the script is run) and what location to hold down your left mouse button (so you aren’t accidentally shooting into a wall and progress isn’t made, or you get shot by hostiles and you get killed). This is only a matter of opening POSTAL and running the command
in your terminal. This window ID is not constant, so if the game is closed and relaunched for whatever reason, you will need to do this again.
Next, load into a level, preferably one where hostiles do not automatically walk towards or shoot you, like The Mines. For this I just used Home because the fence surrounding your spawn gives a narrow gate to enter if anyone wanted to shoot you from your spawn, but it comes down to whatever you want to use. Place your mouse into an ideal and safe position (for Home, point your crosshair at the gate, though it’s also safest to just clear the level; for any other levels, find what works for you), then Alt+Tab into your terminal (for keeping your mouse in the same place) to run the command
and note the returned x and y coordinates. (The command shouldn’t return any “screen” value of any more than 0, but in case it does, refer to the official man pages of xdotool[man.archlinux.org].) I recommend exiting the level after this.
Preparing the script (fun part)
nc=
xdotool windowactivate –sync id mousemove –sync x y
###### You do not need to touch anything below this line. ######
i=1
while [[ $i -le $nc ]] ; do
xdotool mousedown 1
xdotool key g i m m e d a t 3 sleep 10.22
echo “$i of $nc cycle(s) complete”
(( i++ ))
done
xdotool mouseup 1
or visit the script online[jakanz.github.io] and download it into your chosen directory.
Now it’s time to enter the data you gathered from before, most of which is likely self-explanatory. Your number of remaining cycles follows immediately after “nc=”, which establishes how long the script will run using cycles as a metric. Your window ID you obtained will replace “id” on the following line, doing the same with the respective x and y values near the end of the line. Once you save the file, it is ready for action.
Running the script (exciting part)
to indicate this. Assuming you haven’t closed POSTAL, enter the level you chose again. From here, there are three commands to run the script in the command line, all of which accomplish the same thing:
- bash postal_template.sh
- sh postal_template.sh
- ./postal_template.sh
Congratulations! The script is now running and you’re grinding the achievement without any need for input. Assuming you are starting from the very bottom with one million bullets to shoot, this approach takes just above four hours to complete. You can estimate how many hours are remaining in your grind with this formula, where alpha is your uncompleted progress:
Once the script is done and you have your shots in, it does not count if you exit the game from there. You must press F1 to advance levels in order for your shots to count. If you have to restart because of this strange design flaw that is not even indicative of the times this game was released… sorry. :/
Explanation of the script (boring part)
Nerd ♥♥♥♥ ahead. Only enter if you care. There are a few nuances in this section that might be worth reading if you’re having trouble getting the script working and you’ve already reread the whole guide.
The first line, “#!/bin/bash”, is called a shebang – also called a hashbang or poundbang – whereas the comment symbol in shell scripts (#) is the she/hash/pound and the exclamation point (!) is the bang. It’s used as the initial line in scripts to tell the kernel how to execute the script; more specifically, what interpreter to run, bash (Bourne Again Shell) being the interpreter in this case. The line is ignored by the interpreter because the hash comments out the line. This line is not necessarily important as scripts can run without this line, as it’s more of a kernel convention than a rule. However, it is safer than to be sorry, as without this line, the kernel would run whatever is set as its $(SHELL) variable, which could be zsh, ksh, or just plain sh. The bash shell is default of the majority of systems however, so there is nothing to be frantic about here. I just put this in so I could rant about it … and consistency. 😛
The next lines are the only lines the user must change to make the script work. A string of letters and an equals sign (like “nc=” which only stands for “necessary cycles”) is just a variable establisher in shell scripts, which I included so users can plug and play.
The next line, however, is slightly more complex. It’s the first use of the xdotool command with two different components: “windowactivate” and “mousemove”. Both are quite self-explanatory: windowactivate uses a window ID to activate the window, though uses a different method to do so than its sister command “windowfocus”. I chose this over windowfocus due to its ability to switch desktops (“monitors”), meaning more universal capability for this script. mousemove is not like mousemove_relative, in that it moves to absolute screen coordinates rather than relative to the mouse’s position at the time. There is also something else to note here: the –sync flag, featured in both commands. This flag tells the command to wait until the command’s action is done; in this case, both windowactivate and mousemove wait until the window is actually activated and the cursor is actually moved to continue the script. You’ll also notice that two commands can be used in the same line rather than separating each command into its own line, thanks to xdotool’s neat structure.
The next line establishes a “while” loop. This is the only time you’ll see double brackets, as it’s the only time an expression is needed to create the condition for the loop. Inside the condition are three components: the call for the value of variable i, the flag -le to compare two values with “le” being “less or equal to”, and the call for the value of variable nc. The logic is basically this: “while i is less than or equal to nc, do whatever the following says. Otherwise, skip to the end of the loop.” There wasn’t any naming convention for variable i other than it’s what I commonly used in “for” loops in JavaScript, when I still bothered with that nonsense.
The next xdotool command is just holding the left mouse button (indicated by the “1”) down to shoot, now that POSTAL is focused and the cursor is in its desired location. This is in the loop because if the user accidentally clicks, it will go back to holding down the left mouse button at the start of the next cycle. Otherwise, the user would be forced to do math and revise the script to still end the script when they get the achievement stat… Smart, eh?
The next line is what makes the magic happen: it enters the cheat code “gimmedat” to obtain a full backpack of spray cannon ammunition and presses “3” to select the cannon. (This may be something different if you ♥♥♥♥♥♥ with your keyboard settings for whatever reason.) Then, while the mouse button is held down and shooting the cannon, the program waits 10.22 seconds (the approximate time of a cycle) until continuing with the rest of the script. Since this is a loop, this will be executed until all the remaining cycles are done.
The next line just involves a basic CLI command, containing similar calls for variables. “echo” is a built-in command for displaying lines of text in the terminal. Here, the i and nc variables are called again to indicate how many cycles have been done out of the ones necessary to complete the script and achievement. This is the first sight of the elusive double-parentheses to calculate something: nc minus i, the number of remaining cycles.
The next line also contains these double-parentheses to increase i by one. This is done using ++, an operator to increase a variable by one. Alternatively, there is also “i += 1” or even “i = i + 1”, but those are boring as hell.
The next line tells the program to move on with the rest of the file now that the loop’s condition is no longer met. i is greater than nc now.
The final line, “xdotool mouseup 1”, does exactly what you think it does… assuming you read what “xdotool mousedown 1” was about. Not much, really.
Nerd ♥♥♥♥ has ended.
Gallery
Tux says: I regret nothing.
Conclusion
awards pls i was up until 4:30 at night writing and revising this guide
where’s the damn “give me awards” gif when you need it (i need positive reinforcement)
And that wraps up our share on POSTAL: “Bulletstorm” achievement guide for Linux users. If you have any additional insights or tips to contribute, don’t hesitate to drop a comment below. For a more in-depth read, you can refer to the original article here by jakanz, who deserves all the credit. Happy gaming!