Translating QuakeC to Python

The QuakeC -> Python translator has been tested against the deathmatch sourcecode that was supplied with the Quake1/QuakeWorld source release, and CTF 4.21d.

The Python code that's produced may not be entirely optimal, but should be completely runnable as long as a few minor QuakeC bugs are fixed first.

Usage: python qc2python.py <qc-source-dir> [<output-dir>]

Example: python qc2python.py f:\quake\progs py_dm

The qc-source-dir should be the place where your progs.src and *.qc files reside. If you omit the output-dir, the translated game code is placed in the qc-source-dir.

There is also a quick debugging mode, for translating a single QC source file and outputting the result to stdout. To do this, just supply the name of a single QC file instead of a qc-source-dir (this was useful mostly for testing the translator against small snippets of QC code to make sure various constructs were converted properly).

Warnings

The translator will print warnings if:

The Translated Code

Each QC source file will be translated into a single Python module. Comments are retained wherever possible, and overall, the structure of the Python module should be very close to the original QC file.

Every module starts off with two lines importing references from the qwpython package for the QWPython runtime engine, the Vector class constructor, and the QC runtime emulation object. Then, any dependencies on other translated QC modules appear as import statements.

Each translated function is declared with an extra parameter: *qwp_extra, to absorb any unexpected parameters passed to the function. QuakeC seemed to ignore that sort of thing, but Python doesn't like it. Many of these are unnecessary, and can be taken out - this was just a brute-force way of insuring that the translated code would run right out-of-the-box.

If a QC function declared any local variables, those variables are initialized to 0, Vector(0,0,0) or engine.world at the top of the function. This was another brute-force way of insuring that the translated code would run, since in Python, a variable doesn't exist until something is assigned to it. If you are sure that any possible first reference to a variable is always an assignment (even taking if statements and such into account), then the initial assignment can probably be removed in most cases. Here's an example from plats.py:

    def func_train_find(*qwp_extra):
        targ = engine.world
        targ = qc.find(qc.world, 'targetname', qc.self.target)
        qc.self.target = targ.target
        qc.setorigin(qc.self, targ.origin - qc.self.mins)
        if not qc.self.targetname:
            #  not triggered, so start immediately
            qc.self.nextthink = qc.self.ltime + 0.1
            qc.self.think = train_next

That first assignment of engine.world to targ is unnecessary, and can be removed. A fancier translator that looked ahead and analyzed the functions a bit could avoid that sort of thing - but it's relatively harmless, and can be cleaned up by hand (someone is going to modify this Python code, right? otherwise what's the point? might as well leave it in QC if it isn't going to be altered).

At the end of each module will be an extra function to reinitialize the global variables that appear in that module (for use at level changes), named qwp_reset_<module-name>.

A module named __init__.py is created to be the entrypoint for the game, basically, it:

Python for QC programmers

A couple quick notes about a few key things about Python that are different from QC:


$Id: translate.html,v 1.3 2001/02/05 16:38:13 barryp Exp $