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).
The translator will print warnings if:
triggers.qc
).
If you're translating stock DM or CTF, and have fixed the known bugs, then
the warnings should be ignored, since in those cases the translator is doing
the right thing. If you're translating some other QW mod, look at those warnings
closely, and you might catch a small glitch in your original QC 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:
A couple quick notes about a few key things about Python that are different from QC:
a.x = 7
, you'd have to write: a = Vector(7,
a.y, a.z)
.a % b
will result in a new vector set to the values (b.x, b.y,
b.z), but in the case of values that are None
, the corresponding
field from 'a' is copied. This works as an augmented assignment, so the equivalent
of QC's a.x = 7
can be written in Python as: a %= Vector(7,
None, None)
. x = 1 def foo(): x = 2 foo() print xThat assignment of 2 to x is to a local version of x, not the global one, so the print statment will print 1, not 2. You'd have to add a '
global
x
' statement to the top of the function to get the global x to be set
to 2. You'll see this in action in the qwp_reset_*
functions
at the end of each module, which are full of global
declarations.
Without them, the reset functions wouldn't actually reset the global variables
- they would just be setting local variables of the same name$Id: translate.html,v 1.3 2001/02/05 16:38:13 barryp Exp $