Tuesday, October 23, 2012

Super Smash Bros., Combos, and You - an article on a theoretical combo system for SSB

Super Smash Bros. has something of a mixed history as far as combos go. The original SSB64 had combos galore - most of the characters had combos that could take an as-of-yet untouched opponent and KO them without a single chance to dodge or counter - the definition of a "true" combo. Super Smash Bros. Melee significantly reduced the stun the average move does to your opponent, so combos (true combos anyway) became weaker and shorter compared to SSB64.

Now, with the latest release in the SSB series - Super Smash Bros. Brawl - true combos are practically non-existent, meaning the guaranteed damage the average character in the cast can do is typically limited to one or two moves in a row. This may not sound important, but it has several ramifications:
  • Lack of combos means mistakes aren't as costly. In the typical fighting game (SSBM and SSB64 included), 2-5 mistakes might mean a stock (or the game). SSBB, on the other hand, typically lets you get away with more than a dozen mistakes before you lose.
  • The skill ceiling is significantly lowered. SSBB pros can punish mistakes no harder than intermediate players, with the possible exception of what's called "gimping" - KO'ing your opponent with relatively weak move, usually used away from the stage edge.
  • Comebacks become a lot harder, since you'll typically have to repeatedly use one-off attacks, while only a few attacks (many times just one well-placed one) from your opponent will cost you the game.
What I suggest is to give SSB a combo system/mechanic. I'm not going to describe what I have in mind for the system upfront - rather, I'll evolve it over the course of this article, which I think will lead to a better understanding of how a "true" combo system would significantly help SSB and alleviate the aforementioned issues Brawl has. So let's get started!

The first step is to see what other fighting games use. The combo mechanic you most often see in other games is this thing called canceling. Basically, canceling let's you literally cancel one move's animation frames into an entirely different move altogether. Depending upon the game, you can only cancel a move if it touches the opponent (regardless of whether or not it does damage), and for the purposes of this article, we'll assume that's the case for our combo system. Additionally, you can typically only cancel regular attacks into heavier regular attacks (think SSB's standard attack/auto combo) or special attacks.

So now we have our base mechanic. How do we apply it to SSB? Let's assume we can cancel a standard attack into a tilt attack or special attack, we can cancel a tilt attack into a smash attack or special attack, and we can cancel a smash attack into a special attack. So now, every character has this basic combo: Standard attack > tilt attack > smash attack > special attack.

This is pretty good already, but this system suffers from the same issue Brawl has: There's little - if any - room for improvement over the simple combo I just mentioned. The skill ceiling issue remains basically untouched. We need to figure out a way to allow creativity within our little combo system. What can we do to fix this problem?

We have two options: We could further extend the boundary of what can or cannot be canceled, or we can come up with another method of extending combos. The first method will simply lengthen our previous combo, while the latter's benefit will be dependent upon how versatile the introduced sub-mechanic is. We'll try the latter approach, since it helps alleviate the skill ceiling issue Brawl suffers from. So without further ado, I give you: The launcher.

Simply put, a launcher is a move that, like the name implies, launches the opponent up into the air. You can also typically cancel the launcher's animation with a jump if the launcher hurts the opponent, and for our combo system, we'll also allow launchers to be canceled into a dash, which should allow for a bit more creativity as well.

We have to integrate launchers with the little cancelling hierarchy we defined earlier now. Let's insert launchers between smash attacks and special attacks, so that our standard combo now looks like: Standard attack > tilt attack > smash attack > launcher + aerial attack or special attack.

It's not much, but this combo system is already shaping up to be relatively open-ended. However, since we've been focusing on adding new features to it, we've been left with a lot of loose ends to tie up:
  • Knockback (not to mention DI) will effect the viability of a combo - i.e, an opponent might be knocked back far enough that even if you cancel, the new move will not connect. Something needs to be done about this.
  • Hitstun - the amount of time the opponent is stunned and unable to do anything after being hit with one of your moves - will probably need to be increased on average, at least relative to Brawl. Otherwise, even if you perfectly cancel a move into another move, your opponent might recover before the second move's active frames activate.
  • It's conceivable that the combo system could possibly be abused to the point of infinite combos. We obviously can't think of all possible combos, so we should put in some sort of mechanic that will prevent combos from becoming excessively long.
Let's tackle knockback first. We obviously can't take knockback completely out of the system - it's too much a part of SSB to remove it now. So I propose that the hitlag system normally reserved for dramatic, powerful attacks be applied to all moves in the game, with about 5-10 frames of hitlag per hit. Those frames will be the "cancel window" during which you can cancel to another move and be guaranteed that it will connect - no knockback will be applied until after the cancel window has passed. Launchers will have set vertical knockback to make comboing easier, similar to Falco's shine in SSBM.

For those not familiar with the hitlag (also known as "freeze frame") system, hitlag is basically a period of time after which a move connects with an opponent during which the game is, for all intents and purposes, frozen - neither the attacker nor the defender can move during the hitlag period.

This doesn't address the tricky problem that is DI (Directional Influence), however. It's possible in SSBM and SSBB (SSB64 didn't have DI) to use DI to shift the direction in which you get launched and thus escape combos. Whether or not that's a good thing probably comes down to personal opinion, but DI is here to stay in all likelihood, so I'd prefer to design our theoretical combo system to incorporate DI.

The way I see it, the easiest way to incorporate DI into our combo system is to allow DI only after the cancel window on each hit has passed. This brings up a dilemma: What about multi-hit moves? I want to keep comboing as offense-oriented as possible, and thus have relatively few options - if any - to break out of a combo, so I think having a cancel window after each hit, but no knockback and DI until after the cancel window for the final hit has passed is a good idea. Launchers probably shouldn't be DI-able for similar reasons, so let's assume that we can't DI out of a launcher as well.

Now we only have to deal with infinite combos, something a lot of fighting games don't get right. Even the borderline combo-less SSBB had a few infinites here and there, so we'd better take extra caution with our combo system, since it's a lot easier to chain multiple moves back-to-back. Again, taking a look at what other fighting games typically do to alleviate this, I now introduce: hitstun deterioration.

In a nutshell, hitstun deterioration gradually lowers the amount of hitstun of each successive hit in a combo. Eventually, the hitstun of each hit will be practically 0, and the opponent will be able to easily escape the combo. It's obvious that hitstun deterioration could possibly limit legitimate non-infinite combos, as well as put characters with lots of multi-hit moves at a disadvantage, but it's probably the best defense against infinite combos out there right now.

Let's take a quick review of what our combo system's main mechanics are (this is a good TL;DR paragraph if you skimmed over the other parts of the article):

  • Canceling. We can cancel moves into certain other moves in this order: Standard attack > tilt attack > smash attack > launcher + aerial attack or special attack.
  • Cancel windows. There's a small window of opportunity after each hit of a move (about 5-10 frames), during which you can cancel the current move into another move, as per our canceling mechanic defined earlier. No knockback is applied (and DI is impossible) until after the cancel window is over.
  • Launchers. We can perform a launcher, which is basically a move which launches the opponent into the air with set vertical knockback, to perform an aerial combo. If the launcher connects with the opponent, you can cancel the launcher into a jump or a dash. You cannot DI out of a launcher.
  • Hitstun deterioration. The hitstun of each successive hit in a combo gradually decreases to almost 0, thus effectively preventing infinite combos. Note that this doesn't prevent a zero-to-death combo, just infinite combos.

So there you have it. We evolved a theoretical combo system around SSB's unique mechanics, ironed out some minor kinks, and even introduced a few unique mechanics of our own along the way. It's probably not perfect, and might have some errors I've overlooked while I wrote this article, but it's a simple, solid combo system that should be enjoyable by newbies and professionals alike. So that said, it's time for closing statements. :)

  • Project M, a very popular mod for SSBB, includes a combo system for Lucario very similar to the one described here. The most notable differences is that the cancel window system described here is missing, and Lucario's launcher (his up smash) does not have set knockback, meaning it's better as a standalone kill move, but somewhat hard to use at times as a launcher. Hitstun deterioration is also missing, and all his combos are DI-able as far as I know, but the system is still quite similar to the one in this article.
  • It would be feasible to make a mod for SSBB that implements our theoretical combo system, but although I'm not lacking in programming skills, I'm still quite unfamiliar with modding SSBB in general, unfortunately.
  • SSB4 will be coming out sometime next year (2013), and Masahiro Sakurai (SSB's creator) has stated that the game will be taking a "new direction" compared to previous SSB titles. Namco - who develops the popular fighting game series Tekken - is heading development of SSB4, so who knows, you might see something like this in SSB4.
Thanks for taking the time to read through this giant wall of text!

Thursday, July 19, 2012

How to use sys.meta_path with Python

I was asked on Reddit a short while ago as to how to use sys.meta_path, which is an extremely valuable tool that can be used to implement import hooks. Since it seems there's little documentation as to how to use it properly, I decided to write an example that shows basic usage of sys.meta_path. I posted the example on Reddit in the thread I linked to, but I've put it here for posterity - enjoy. :)

import sys


class VirtualModule(object):

   def hello(self):
      return 'Hello World!'


class CustomImporter(object):

   virtual_name = 'my_virtual_module'

   def find_module(self, fullname, path=None):
      """This method is called by Python if this class
         is on sys.path. fullname is the fully-qualified
         name of the module to look for, and path is either
         __path__ (for submodules and subpackages) or None (for
         a top-level module/package).

         Note that this method will be called every time an import
         statement is detected (or __import__ is called), before
         Python's built-in package/module-finding code kicks in.
         Also note that if this method is called via pkgutil, it is possible
         that path will not be passed as an argument, hence the default value.
         Thanks to Damien Ayers for pointing this out!"""

      if fullname ==  self.virtual_name:
      
         # As per PEP #302 (which implemented the sys.meta_path protocol),
         # if fullname is the name of a module/package that we want to
         # report as found, then we need to return a loader object.
         # In this simple example, that will just be self.

         return self

      # If we don't provide the requested module, return None, as per
      # PEP #302.

      return None

   def load_module(self, fullname):
      """This method is called by Python if CustomImporter.find_module
         does not return None. fullname is the fully-qualified name
         of the module/package that was requested."""

      if fullname != self.virtual_name:
         # Raise ImportError as per PEP #302 if the requested module/package
         # couldn't be loaded. This should never be reached in this
         # simple example, but it's included here for completeness. :)
         raise ImportError(fullname)

      # PEP#302 says to return the module if the loader object (i.e,
      # this class) successfully loaded the module.
      # Note that a regular class works just fine as a module.
      return VirtualModule()


if __name__ == '__main__':

   # Add our import hook to sys.meta_path
   sys.meta_path.append(CustomImporter())

   # Let's use our import hook
   import my_virtual_module
   print my_virtual_module.hello()

Note: The original PEP that defined the sys.meta_path protocol is PEP #302, which you can read here.

Saturday, July 14, 2012

Reverse-engineering LEGO Racers 1 - part 1

First off, a brief description of LEGO Racers 1: It basically was a racing game released back in 1999 (and then re-released in 2001) where you could make your own car (and driver) out of LEGO bricks and then race it against half-a-dozen or so AI cars or a friend, on one of about two dozen tracks. Sounds fun, right? It is.



Sadly, since the game was released so long ago, it can be difficult to run it on a modern OS - the 1999 release of the game had DRM that required the disk, for example - not to mention there's quite a bit of dummied-out content (several shortcuts are missing, most famously from the Knightmare-athon track) that I and probably several others would love to play around with and modify. And that's why I've decided to write a drop-in replacement for the LEGO Racers 1 game engine.

It's not a new idea - I can bring up forum threads from up to 2 years ago of people attempting to mod LEGO Racers 1. That being said, these people are trying to mod the game itself, not create a replacement for LEGO Racers 1's game engine. I want to create a game engine instead of attempting to mod the game itself for several reasons:
  • A mod of the game still would have issues with the DRM and compatibility issues I previously mentioned; one would still need the original game to play the mod.
  • A mod of the game would not be able to add new content without removing existing content; I doubt, for instance, you could add new circuits, bricks, chassis, or piece sets (you unlocked the pieces of each bosses car when you beat them) without removing existing content.
  • A mod of the game would still be subject to the limitations of the original game engine - AI cars still wouldn't follow shortcuts, the AI behavior itself couldn't be changed, no new racing modes could be added, racing with more than 2 human players wouldn't be possible (and even then, you'd need a joystick), etc. In other words, only content would be moddable, not game logic.
There would be many advantages to making a game engine as well:
  • Not only would only the data files from the original game be required to play, but it would be feasible to create a replacement for the original data files as well, so you wouldn't even need the original game to play (ala PrBoom + freedoom).
  • A replacement for LEGO Racers 1's game engine would allow everything to be moddable - powerups, tracks, circuits, AI behavior (imagine the AI being a script the game engine runs instead of being part of the engine itself), bricks, piece sets, cutscenes, animations - everything.
  • Making a replacement game engine instead of modding the original game makes modding much easier and more approachable to a new modder.
Right now, I intend to make the engine open-source (under the Apache License 2.0, probably), and host it on GitHub, to make it more accessible to potential developers. If you'd like to help out (that said, I haven't started yet), let me know. :) I'll try to keep updating my blog as progress on reverse-engineering LEGO Racers 1's data formats is made.

Friday, July 13, 2012

Minetest Triforce

In case you're not familiar with it, Minetest is basically a free, open-source clone of Minecraft, plus some new stuff like Lua mod support. Anyway, I made a very large Triforce on gameboom's mt1.gameboom.net (port 30000) Minetest server some time ago, and this is the result:

Daytime


Nighttime


Monday, July 9, 2012

Evo 2012 - one hype event!

In case you're not familiar with it, Evo is a international fighting game tournament (though Mario Kart was on the roster one year a few years back) held every year in Las Vegas, Nevada. It attracts thousands (if not tens of thousands) of participants and spectators every year from places like Taiwan, Japan, and South Korea. Indeed, many of the top players come from those countries. The live video stream of the tournament attracted almost a hundred thousand viewers from all over the world at its peak, which is an amazing thing.


I wasn't able to watch the tournament in person, but I was able to watch the livestream for the entirety of the Super Street Fighter IV AE 2012 and Ultimate Marvel vs. Capcom 3 events. There were quite a few exciting matches - for me, here are the highlights of the tournament:






Hopefully, I'll be able to watch Evo in person next year, and possibly compete in the Super Street Fighter IV AE 2012 section if I ever buy the game.

Switching to Blogger

I exported my WordPress blog to Blogger - I think I'm going to enjoy the change. We'll see about that in the coming months, though. :)

Sunday, June 10, 2012

Switching blog licenses.

I've given it some thought, and I've made a decision: I'm switching the license for the articles I write on my blog from the CC-BY-NC-SA to CC-BY-SA.  I'm switching for two reasons:

  • It lets my articles be re-used/re-posted in far more places I do want it to be used (Wikipedia, other places using the CC-BY-SA, etc...)

  • I don't think anyone's going to plagiarize my work anytime soon - besides, at the very least, they have to give me credit (the BY clause).


Besides, I think the more liberal licensing terms make the blog more attractive to FOSS enthusiasts, which is a big plus for me since I need all the publicity I can get. Hopefully I'll see the rewards of switching to the CC-BY-SA license in a year or so. :)

Tuesday, May 29, 2012

Adventures in optimization

Yesterday was the first day I ever had to seriously optimize some code I had written. The code in question? A point cloud implementation.

When I started work on said implementation, I coded the library in pure Python, and tried it out on a 50,000-point volume. It took 15 seconds just to initialize and move the volume - completely unacceptable. I had a lot of optimization work to do.

The first technique I tried was just a faster algorithm. I switched from using a SQLite database to flat dictionaries, which gave a speed boost of around 2 seconds. Next I tried binding expensive non-local variables to local scope - an extra second or so. Now I was out of ideas (most of the performance-intensive code was just simple for loops) - I decided to re-write the code in Cython.

Simply compiling my library took the performance up to about 7 seconds; adding static typing in strategic spots took the performance even farther - to 2 seconds. A few Cython-specific optimizations further (binding class member variables to local scope, for one), and my library could process a 50,000-point volume in about 0.35 seconds.

Unfortunately, that's still way to slow for my needs - I need 0.1 seconds or less (preferably 0.05 or less) per 50,000 points, so I still have a ways to go. What I'll probably do is re-code some of the library in flat C++, and then access that from Cython. I'll try to keep my blog updated on whether or not I'm successful in this venture. :)

Friday, April 13, 2012

My toy scripts - now available on SourceForge!

I've decided to make good use of SourceForge's per-developer project space - a really nice feature, by the way - and upload all the toy scripts I've made over the years to https://sourceforge.net/u/openblocks/code/. All the scripts are licensed under the 3-clause BSD license, so feel free to give them a look and make your own modifications. :)

Keep in mind that since I use Linux as my main operating system, some of the toys that are shell scripts won't work on Windows, unfortunately.

Wednesday, April 11, 2012

The hashcash algorithm

Yeah, it has a weird name, but it's one of the most interesting (and effective) anti-spam algorithms out there: Hashcash. How does it defeat spam without the end-user even knowing a spam check is taking place? Read on.

No, this isn't a Bayesian filter-like algorithm; this is something completely different. Hashcash involves inserting a piece of Javascript code into your site's comment form that sends a server-generated key as part of the comment form's data. If the sent key doesn't match the one the server sent as part of the comment form, the comment is marked as spam and not posted. Amazingly simple. And this all happens behind the scenes, without your users even knowing a spam check is going on!

Now, this algorithm works solely on the premise that spambots are incapable of running Javascript, so if spammers come up with a spambot that is capable of running Javascript, Hashcash would be in hot water. But again, no such spambot currently exists, so Hashcash is currently a viable spam-blocking algorithm.

I think Hashcash is such I good idea, I'm going to give it a test run on this site using the WP Hashcash plugin for WordPress. Hopefully I won't have to manually deal with spam for a long time to come. :)

Wednesday, March 28, 2012

Do we need a new FOSS license?

Come on, admit it: You've been involved in at least one (probably 3 or more) licensing "discussions" with your fellow FOSS peers. :P Like you probably already know (and like I covered in one of my previous posts), these "discussions" revolve mainly around whether or not the GPL is, in fact, a truly free license. I'm not going to discuss that here (for brevity), but what I will discuss is whether an "compromise" license that sits right between the GPL and a permissive license in terms of restrictions is possible.

First, we need to know what our new license can and cannot do. According to the Open Source Definition (which you can read for yourself here), here are some things our new license couldn't do:

  • Prevent commercial re-distribution. Commercial re-distribution is very different from proprietary re-distribution, by the way

  • Prevent (possibly derivative) products issued under the same license as ours

  • Restrict other software distributed on the same medium as ours


Okay, so now we now what we can't do, let's figure out what we can do.



  • The biggest problem most people have with the GPL is that it prevents other, non-GPL, FOSS software from using GPL'ed products (because the licenses are incompatible). We need to figure out a way to solve this issue in order to come up with a true "compromise" license.

  • The counter-argument against permissive licenses is that they allow proprietary derivatives of your project. Whether or not this is an issue is completely up to you, but for the purposes of this post, I'll assume the answer is "yes."

  • The Open Source Definition does allow open-source licenses to "pick and choose" what derivative projects can be licensed under; the most notable open-source license that does this is the GPL - you can derive from a GPL product and use the AGPL for your code if you so choose


What if we could allow anyone to derive from a product licensed under our hypothetical license as long as they used our new license, or an OSI-approved license? While this has the obvious disadvantage of preventing a BSD-licensed project which uses our hypothetical project from being used in a proprietary product, it's a pretty big step towards an actual "compromise" license.

That's as good a compromise as I can think of for now. Hopefully I can think of a better one in the future. :)

Sunday, March 11, 2012

Setting up MinGW32 on Ubuntu

Finally, a non-controversial topic :)

Having a cross-compiler that can compile Windows executables on a Linux machine can be an extremely useful tool to have, since it prevents you from having to install WINE or a virtual machine just to generate Windows executables for your software project. I find myself often in need of such a tool, and since there doesn't seem to be any up-to-date tutorial on how to set up a MinGW32 cross-compiler, I decided to write one. :)

Okay, so here we go: First, install the gcc-mingw32 package with the following command:
sudo apt-get install gcc-mingw32

And we're basically finished. To use your newly-installed cross-compiler, use the following command:
i586-mingw32msvc-gcc

As a final finishing touch, I add a soft link that allows me to access my new cross-compiler with shorter name, like so:
ln -s $(which i586-mingw32msvc-gcc) gcc-mingw32

If you execute that command in your $HOME/bin directory (assuming, of course, that that directory is on your $PATH), you can access your cross-compiler via gcc-mingw32 instead of the longer i586-mingw32msvc-gcc.

Let's test our cross-compiler on a simple piece of software: Lua 5.1. I'll assume you've already unpacked Lua into some convenient directory, and have opened a terminal there. I'll also assume you made the soft link I talked about earlier, but that's no big deal - if you didn't, just replace gcc-mingw32 with i586-mingw32msvc-gcc.

Lua makes things easy on us by having 99% of the compiler options already set up for us; we just have to tell it where to find our cross-compiler - otherwise, it will find the non-cross-compiling installation of GCC:
make mingw CC=gcc-mingw32

That wasn't too hard either. :) Here's what that command outputs on my system:
cd src && make mingw
make[1]: Entering directory `/home/(my username)/Downloads/lua-5.1/src'
make "LUA_A=lua51.dll" "LUA_T=lua.exe" \
"AR=gcc-mingw32 -shared -o" "RANLIB=strip --strip-unneeded" \
"MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe
make[2]: Entering directory `/home/(my username)/Downloads/lua-5.1/src'
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lua.o lua.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lapi.o lapi.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lcode.o lcode.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o ldebug.o ldebug.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o ldo.o ldo.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o ldump.o ldump.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lfunc.o lfunc.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lgc.o lgc.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o llex.o llex.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lmem.o lmem.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lobject.o lobject.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lopcodes.o lopcodes.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lparser.o lparser.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lstate.o lstate.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lstring.o lstring.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o ltable.o ltable.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o ltm.o ltm.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lundump.o lundump.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lvm.o lvm.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lzio.o lzio.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lauxlib.o lauxlib.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lbaselib.o lbaselib.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o ldblib.o ldblib.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o liolib.o liolib.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lmathlib.o lmathlib.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o loslib.o loslib.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o ltablib.o ltablib.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o lstrlib.o lstrlib.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o loadlib.o loadlib.c
gcc-mingw32 -O2 -Wall -DLUA_BUILD_AS_DLL -c -o linit.o linit.c
gcc-mingw32 -shared -o lua51.dll lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o lstrlib.o loadlib.o linit.o
strip --strip-unneeded lua51.dll
gcc-mingw32 -o lua.exe -s lua.o lua51.dll -lm
make[2]: Leaving directory `/home/(my username/Downloads/lua-5.1/src'
make[1]: Leaving directory `/home/(my username/Downloads/lua-5.1/src'

Hey, looked like it worked. Let's try running our new executable with WINE:
wine src/lua.exe
fixme:advapi:RegisterTraceGuidsW (0x100778a, 0x100a060, {485e7de8-0a80-11d8-ad15-505054503030}, 1, 0x33fe00, (null), (null), 0x100a068,): stub
fixme:advapi:RegisterTraceGuidsW (0x100778a, 0x100a080, {485e7de9-0a80-11d8-ad15-505054503030}, 1, 0x33fe00, (null), (null), 0x100a088,): stub
fixme:advapi:RegisterTraceGuidsW (0x100778a, 0x100a0a0, {485e7dea-0a80-11d8-ad15-505054503030}, 1, 0x33fe00, (null), (null), 0x100a0a8,): stub
fixme:advapi:RegisterTraceGuidsW (0x100778a, 0x100a0c0, {485e7deb-0a80-11d8-ad15-505054503030}, 1, 0x33fe00, (null), (null), 0x100a0c8,): stub
fixme:advapi:RegisterTraceGuidsW (0x100778a, 0x100a0e0, {485e7dec-0a80-11d8-ad15-505054503030}, 1, 0x33fe00, (null), (null), 0x100a0e8,): stub
fixme:advapi:RegisterTraceGuidsW (0x100778a, 0x100a100, {485e7ded-0a80-11d8-ad15-505054503030}, 1, 0x33fe00, (null), (null), 0x100a108,): stub
fixme:win:RegisterDeviceNotificationW (hwnd=0x14fae8, filter=0x65e93c,flags=0x00000001) returns a fake device notification handle!
Lua 5.1 Copyright (C) 1994-2006 Lua.org, PUC-Rio
>

And there you have it: We went step-by-step through the process of installing MinGW32, adding a convenience soft link, and compiling a simple piece of software - Lua.

Happy cross-compiling!

Monday, March 5, 2012

On piracy

Yes, another controversial topic: Piracy. It's pretty prevalent today - you probably know at least 5 people that have pirated software, and you might have pirated some software yourself; I myself have pirated software in the past, albeit before I knew of the legal and moral issues surrounding it.

So what makes piracy so popular? The most obvious reason is you get a piece of software you'd normally have to pay for for free, and everyone loves that. Except the people who wrote the software, and that's what this short essay is going to be about.

First let's get our terms straight: What is piracy? It's basically the act of downloading a copy of a piece of software that was not made by the software's author - in other words, copyright infringement. Now, is there anything legally wrong with piracy? Quite a bit. How about morally? Er, that's not so clear in some cases.

When you pirate a piece of software that's still being distributed in some legal form, you're basically saying: "Mr. Software Author, I like the software you wrote, but I don't like xxx about it (price, DRM, etc...). Shame on you, so I'm going to take your software and use it for free." I can't really see any way to justify this line of thinking, at least from Mr. Software Author's point of view.

You might say you're not hurting Mr. Software Author by pirating his software, and you might be right, depending upon how rich he is. But that doesn't change the fact that you took something that wasn't yours. You're not entitled to Mr. Software Author's product, and if you don't want to use it the way he wants you to use it, don't use it at all.

If Mr. Software Author's product is tainted with DRM, and that's the reason you're giving for pirating his product, consider this: Will your circumvention of the DRM Mr. Software Author set in place cause him to remove the already present DRM? No - on the contrary, he'll probably add more! Instead of pirating a DRM'ed product (which is still taking something that isn't yours), support a non-DRM'ed one instead. Lack of customers will change Mr. Software Author's opinion on DRM more than anything else.

Now, what do you do in the (very common) case of software whose parent company is either defunct or no longer distributes the software in question? This is both a legal and moral gray area. I mean, technically you're still guilty of copyright infringement, but the copyright owner no longer exists, so it's a legal gray area. It's a morally gray area because while you're still taking something that really isn't yours, you're offered no alternative method to download the software in question.

What about if the parent company exists, but they no longer distribute the software in question? You often see this sort of thing happening with arcade ROMs. My personal take on this case - IANAL - is it's fine (morally so - this is a legal gray area) to pirate arcade ROMs, but only if the parent company offers no way to get the ROMs via other means. For example, Capcom offers Street Fighter Alpha 2 on the Wii Virtual Console platform, but not Street Fighter Alpha 3. So pirating Alpha 3 would be fine by me, but I wouldn't pirate Alpha 2.

I hope this essay on piracy has been an interesting read for you. I also hope it makes you think about the moral and legal implications of piracy a bit more - hey, you might even solve this whole legal mess. :)