Copy Link
Add to Bookmark
Report
Doom Editing Digest Vol. 01 Nr. 478
From: owner-doom-editing-digest
To: doom-editing-digest@nvg.unit.no
Subject: doom-editing-digest V1 #478
Reply-To: doom-editing
Errors-To: owner-doom-editing-digest
Precedence: bulk
doom-editing-digest Sunday, 12 November 1995 Volume 01 : Number 478
Quake Scripting Language
Hexen scripting language
script decompiler
Re: Quake Scripting Language
Re: Stand Alone Node builder
Re: Hexen scripting language
Re: Hexen scripting language
Re: Hexen scripting language
Quake Scripting Language
----------------------------------------------------------------------
From: Romero <johnr@idtokay.idsoftware.com>
Date: Fri, 10 Nov 95 18:52:04 -0600
Subject: Quake Scripting Language
Hexen has a scripting language, Quake has a programming language. There is no
"scripting" per se in Quake, it's all programming.
Hence, there is NO similarity. And yes, Quake will not make Christmas.
Have lots of fun with Hexen!
- ---
+-----------------------------+
| John Romero |
| id Software, inc. |
| johnr@idsoftware.com |
| 214.613.3589.11 |
+-----------------------------+
------------------------------
From: Romero <johnr@idtokay.idsoftware.com>
Date: Fri, 10 Nov 95 18:57:27 -0600
Subject: Hexen scripting language
> Gosh, and I thought John had better things to do. Like writing
> QuakeEd. So he can write a quake editor and an hexen editor at
> the same time, while playing deathmatch half of the day?
>
> However, that confirms the impression that the hexen script language
> may be real close to .QP, and that the intermediary form of .QP might
> be that strange 'compiled' form of hexen behavior.
>
> Another reason for Luc to build a hexen script decompiler.
>
Nope. HexenEd is an extension of DoomEd, which i wrote. Chris Rhinehart and
Ben Gokey wrote the extensions to it and created HereticEd, then extended it
more into HexenEd (all versions are NEXTSTEP only). John Carmack and I
created QuakeEd which has nothing to do with our previous editors. I also
don't deathmatch 1/2 the day -- i'm making Quake all day! I'm the Lead
Designer!
Quake's programming language is called Quake C, which makes our filename
extension .QC. It USED to be .QP but i changed it.
Again, there is NO similarity between Hexen's scripting language and QC.
- ---
+-----------------------------+
| John Romero |
| id Software, inc. |
| johnr@idsoftware.com |
| 214.613.3589.11 |
+-----------------------------+
------------------------------
From: Robert Forsman <thoth@cis.ufl.edu>
Date: Fri, 10 Nov 1995 19:36:02 EST
Subject: script decompiler
OK. I had this done about 2pm, but took a nap. Now it's time for dinner
and I figure I shouldn't keep you waiting any more.
Caveats: This does not properly decompile all of the Hexen wads. There are
some branching constructs I seem to have fucked up. I know for a fact that I
don't do the do-while or do-until, and I'm getting diagnostics that say I'm
misinterpreting some branching spaghetti. I'll fix it eventually.
Caveat 2: You certainly can't turn around and recompile the output. I'm
sure there are semicolons out of place. I also don't do anything with
strings. I need to add argument recognition to the function opcode
recognizer. This will enable me to put strings in their proper place in the
arguments.
One good thing about me doing this first. Nobody has to cough up an ounce
of bud or a kilo, just a case of beer (which is much less illegal). I think
I'm going to go drinking.
Maybe I'll install my new ethernet card first (WOOHOO, my pentium is wired
in 30 minutes!)
#!/usr/bin/perl
@opeqnames = ("+=", "-=", "*=", "/=", "%=", "++", "--" );
@vartypes = ("lvar", "mvar", "gvar");
@opnames = ("+", "-", "*", "/", "%",
"==", "!=", "<", ">", "<=", ">=");
%codes = (
1, "0 proc terminate",
2, "0 proc suspend",
# 3 literal
# 4..8 special proc
# 9..13 special proc const args
# 14..24 infix operators
# 25..27 assignment
# 28..30 variable load
# 31..51 op-assign
# 52 branch
# 53 branch non-zero?
54, "1 proc ignore",
# 54 pop (endcase)
55, "1 proc delay",
56, "1 constproc delay",
57, "2 func random",
58, "2 constfunc random",
59, "2 func thingcount",
60, "2 constfunc thingcount",
61, "1 proc tagwait",
62, "1 constproc tagwait",
63, "1 proc polywait",
64, "1 constproc polywait",
65, "2 proc changefloor",
66, "2 constproc changefloor",
67, "2 proc changeceiling",
68, "2 constproc changeceiling",
70, "2 infix &&",
71, "2 infix ||",
72, "2 infix &",
73, "2 infix |",
74, "2 infix ^",
75, "2 infix !",
76, "2 infix <<",
77, "2 infix >>",
78, "1 func -",
# 79 branch zero ("unless")
80, "0 func lineside",
81, "1 proc scriptwait",
82, "1 constproc scriptwait",
83, "0 proc clearlinespecial",
# 84 case goto
85, "0 proc printbegin",
86, "0 proc printdispatch",
87, "1 proc printstring",
88, "1 proc printdecimal",
89, "1 proc printconst",
##
90, "0 func playercount",
91, "0 func gametype",
92, "0 func gameskill",
93, "0 func timer",
94, "2 proc sectorsound",
95, "2 proc ambientsound",
96, "1 proc soundsequence",
97, "4 proc setlinetexture",
98, "2 proc setlineblocking",
99, "7 proc setlinespecial",
100, "3 proc thingsound",
101, "0 proc printBOLDdispatch",
);
%functions = (
);
sub int_at
{
local ($offset) = @_;
return unpack("I", substr($behavior, $offset, 4));
}
sub decode
{
local ($idx, $base) = @_;
local ($offset) = $idx + $base;
local ($opcode) = &int_at($offset);
local ($arg1) = &int_at($offset + 4);
local ($arg2) = &int_at($offset + 8);
local ($advance, $str); # multiply $advance by 4 before returning
local ($indentadj);
local ($i);
for ($i=0; $i<@curlies; $i++) {
local ($o, $n) = split(" ", $curlies[$i]);
if ($o == $offset) {
if ($o+$n == $breakables[0]) {
shift(@breakables);
shift(@continuables);
}
printf "\t%04d\t%s}\t\n", $offset, " "x($indent-=4);
splice(@curlies, $i, 1);
if ($n) {
return $n;
} else {
$i--;
}
}
}
for ($i=0; $i<@elses; $i++) {
if ($offset == $elses[$i]) {
printf "\t%04d\t%s} else {\t\n", $offset, " "x($indent-4);
# print("} else {\t\n\t");
splice(@elses, $i, 1);
return 8;
}
}
for ($i=0; $i<@cases; $i++) {
local ($o, $n) = split(" ", $cases[$i]);
if ($offset == $o) {
printf "\t%04d\t%scase $n:\t\n", $offset, " "x($indent-4);
splice(@cases, $i, 1);
$i--;
}
}
if (@stack == 0) {
$lastemptystack = $offset;
}
if (defined($codes{$opcode})) {
local ($arity, $fixness, $name) = split(/ /, $codes{$opcode});
$advance = 1;
local (@args);
local ($prefix);
if ($fixness =~ s/^const//) {
$prefix = "const: ";
for ($i=0; $i<$arity; $i++) {
push(@args, &int_at($offset+4+$i*4));
$advance++;
}
} else {
@args = splice(@stack, scalar(@stack)-$arity);
}
if ($fixness eq "proc") {
$str = "$name($prefix".join(", ", @args).");";
} elsif ($fixness eq "func") {
local ($tmp) = "$name($prefix".join(", ", @args).")";
$str = "\t # $tmp";
push(@stack, $tmp);
} elsif ($fixness eq "infix") {
local ($tmp) = "(".join(" $name ", @args).")";
$str = "\t \# $tmp";
push(@stack, $tmp);
} else {
die "bad fixness $fixness for opcode $opcode";
}
} elsif ($opcode == 3) {
$advance = 2;
$str = "\t # literal $arg1";
push(@stack, $arg1);
} elsif ($opcode >= 4 && $opcode < 9) {
$advance =2;
local ($arity) = $opcode-3;
#$str = "special ";
local ($i);
for ($i=0; $i*3<@specials; $i++) {
if ($arity == $specials[$i*3+2] && $arg1==$specials[$i*3]) {
last;
}
}
if ($i*3<@specials) {
$str .= $specials[$i*3+1];
} else {
$str .= "code$arg1";
}
if (@stack >= $arity) {
@args = splice(@stack, @stack-$arity);
$str .= "(".join(", ", @args).");";
} else {
die "Stack is short [@stack]";
}
} elsif ($opcode >= 9 && $opcode < 14) {
local ($arity) = $opcode-8;
$advance =2+$arity;
$str = "";
local ($i, @args);
for ($i=0; $i*3<@specials; $i++) {
if ($arity == $specials[$i*3+2] && $arg1==$specials[$i*3]) {
last;
}
}
if ($i*3<@specials) {
$str .= $specials[$i*3+1];
} else {
$str .= "code$arg1";
}
local (@args);
for ($i=0; $i<$arity; $i++) {
push(@args, &int_at($offset+4+4*$i));
}
$str .= "(const: ".join(", ", @args).");";
} elsif ($opcode >= 14 && $opcode <=24) {
$advance = 1;
$str = "\t # ".$opnames[$opcode-14];
local ($rhs) = pop(@stack);
local ($lhs) = pop(@stack);
push(@stack, "(".$lhs.$opnames[$opcode-14].$rhs.")");
} elsif ($opcode >24 && $opcode<=27) {
$advance = 2;
local ($vartype) = $vartypes[$opcode-25];
#$str = "store $vartype[$arg1]\n";
$str = "$vartype[$arg1] = ".pop(@stack);
} elsif ($opcode >= 28 && $opcode<30) {
$advance = 2;
local ($vartype) = $vartypes[$opcode-28];
$str = "\t # load $vartype[$arg1]";
push(@stack, "$vartype[$arg1]");
} elsif ($opcode>=31 && $opcode <52) {
$advance = 2;
local ($op) = $opeqnames[($opcode-31)/3];
local ($vartype) = $vartypes[($opcode-31)%3];
if ($opcode<50) {
$str = "$vartype[$arg1] $op ". pop(@stack). ";";
} else {
$str = "$vartype[$arg1] $op ;";
}
} elsif ($opcode == 52) {
$advance = 2;
if (&int_at($arg1) == 84) {
$str = "switch (".pop(@stack).") {";
# case statement
for ($i=0; &int_at($arg1+$i*12) == 84; $i++) {
local ($const) = &int_at($arg1+$i*12 + 4);
local ($off) = &int_at($arg1+$i*12 + 8);
push(@cases, "$off $const");
}
local ($breakaddr);
if (&int_at($arg1+$i*12) == 54) {
if (&int_at($arg1+$i*12 +4) == 52) { #
local ($off) = &int_at($arg1+$i*12+8);
push(@cases, "$off default");
$breakaddr = $arg1+ $i*12 +12;
} else {
$breakaddr = $arg1+ $i*12 +4;
}
push(@curlies, "$arg1 ".($breakaddr-$arg1));
} else {
print "//funky, unexpected end of case\n";
push(@curlies, "$arg1 ".($i*12));
$breakaddr = ($arg1+$i*12);
}
unshift(@breakables, $breakaddr);
unshift(@continuables, 0);
# print "# new{break,continu}able $breakaddr, 0\n";
$indentadj = 4;
} elsif ($arg1 == $breakables[0]) {
$str = "break";
} elsif ($arg1 == $continuables[0]) {
$str = "continue";
} else {
$str = "br $arg1";
}
} elsif ($opcode == 53) {
$advance = 2;
$indentadj = 4;
if (&int_at($arg1-8) == 52) {
if (&int_at($arg1-4) == $lastemptystack) {
# a while statement
$str = "until (" . pop(@stack) . ") {";
push(@curlies, ($arg1-8)." 8");
unshift(@breakables, $arg1);
unshift(@continuables, $lastemptystack);
# print "# new{break,continu}able $arg1, $lastemptystack\n";
} else {
# an ifelse
$str = "unless (" . pop(@stack) . ") {";
push(@elses, ($arg1-8));
push(@curlies, &int_at($arg1-4)." 0");
}
} elsif ($arg1 > $offset) {
$str = "if (" . pop(@stack) . ") {";
push(@curlies, $arg1." 0");
} else {
$str = "bnz $arg1 " . pop(@stack);
$indentadj = 0;
}
# $str = "bnz $arg1\n";
} elsif ($opcode == 69) {
$advance = 1;
$str = "restart";
} elsif ($opcode == 79) {
$advance = 2;
$indentadj = 4;
local ($handled) = 0;
if ($arg1 > $offset && &int_at($arg1-8) == 52) {
if (&int_at($arg1-4) == $lastemptystack) {
# a while statement
$str = "while (" . pop(@stack) . ") {";
push(@curlies, ($arg1-8)." 8");
unshift(@breakables, $arg1);
unshift(@continuables, $lastemptystack);
# print "# new{break,continu}able $arg1, $lastemptystack\n";
$handled = 1;
} else {
# an ifelse
$str = "if (" . pop(@stack) . ") {";
push(@elses, ($arg1-8));
push(@curlies, &int_at($arg1-4)." 0");
$handled = 1;
}
}
if (!$handled) {
if ($arg1 > $offset) {
$str = "if (" . pop(@stack) . ") {";
push(@curlies, $arg1." 0");
} else {
$indentadj = 0;
$str = "bz $arg1 " . pop(@stack);
}
}
} elsif ($opcode == 84) {
$advance = 3;
$str = "case ==$arg1 br $arg2";
} else {
$advance = 0;
$str = "unknown";
}
unless ($str =~ /^\s*\#/) {
printf "\t%04d\t%s%s\n", $offset, " "x$indent, $str;
if (@stack!=0) {
warn "// previous statement had stack leftovers ";
}
}
$indent += $indentadj;
return $advance*4;
}
while (@ARGV) {
if ($ARGV[0] eq "-specials") {
shift;
local ($fname) = shift;
open(FILE, $fname) || die "Unable to open $fname for read";
while (<FILE>) {
if (/(\d+)\s*:\s*(\w+)\s*\(\s*(\d+)\s*\)\s*[,;]/) {
push(@specials, $1, $2, $3);
}
}
} else {
last;
}
}
undef $/;
$behavior = <>;
$diroff = &int_at(4);
$dirlen = &int_at($diroff);
for ($i=0; $i<$dirlen; $i++) {
local ($idx) = ($i*3+1)*4+$diroff;
print "script ", &int_at($idx), " {\n";
local ($offset) = &int_at($idx+4);
local ($len);
if ($i+1<$dirlen) {
$len = &int_at($idx+16) - $offset;
} elsif (&int_at($idx+12)==0) {
$len = $diroff - $offset;
} else {
# print "length calc. ", &int_at($idx + 16), "\n";
$len = &int_at($idx + 16) - $offset;
}
$j = 0;
while ($j<$len) {
local ($advance) = &decode($j,$offset);
if ($advance > 0 && $advance+$j <= $len) {
#print "$str\n\t";
$j += $advance;
} else {
last;
}
}
while ($j<$len) {
printf "%5d ", &int_at($j+$offset);
if (($j/4+1)%10 == 0) {
print "\n\t";
} else {
# print "\t";
}
$j+=4;
}
print "}\n\n";
if ($indent != 0) {
warn "leftover indentation = $indent\n";
$indent = 0
}
if (@stack) {
warn "leftover stack: [", join(", ", @stack), "]\n";
@stack = ();
}
if (@curlies) {
warn "spare curlies: [", join(", ", @curlies), "]\n";
@curlies = ();
}
if (@elses) {
warn "spare elses: [", join(", ", @elses), "]\n";
@elses = ();
}
if (@cases) {
warn "spare cases: [", join(", ", @cases), "]\n";
@cases = ();
}
if (@breakables) {
warn "spare breakables: [", join(", ", @breakables), "]\n";
@breakables = ();
}
}
$stroff = $diroff + ($dirlen*12 + 4);
$nstrs = &int_at($stroff);
for ($i=0; $i<$nstrs; $i++) {
local ($offset) = &int_at($stroff+($i+1)*4);
local ($tmp) = substr($behavior, $offset);
if ($tmp =~ /^([^\0]*)/) {
print "String $i: $1\n";
} else {
warn "problem extracting string #$i from offset $offset\n";
}
}
------------------------------
From: Jim Wraith <jim@kildare.demon.co.uk>
Date: Sat, 11 Nov 1995 08:39:59 GMT
Subject: Re: Quake Scripting Language
In your message dated Friday 10, November 1995 you wrote :
> Hence, there is NO similarity. And yes, Quake will not make Christmas.
Bummer.
> Have lots of fun with Hexen!
>
Looks as though I'll have to now :)
<sulk mode on>
------------------------------
From: Michael Deckerd <deckerd@gonzo.wolfenet.com>
Date: Sat, 11 Nov 1995 10:56:14 -0800
Subject: Re: Stand Alone Node builder
At 06:29 PM 11/10/95 EST, you wrote:
>Matt --
>
>You can get ZenNode at ftp.cdrom.com as ZEN095.ZIP. It works in DOS, Win95,
>NT, and OS/2.
>
>- John
>
>-----------------------
>John W. Anderson
>dr_sleep@cis.compuserve.com @ 10-Nov-95 18:24:35 EST
>
>
...Okie, now where can you get HETH-B13? The closes version I can find is
HETH-B11...
------------------------------
From: Walter Meyer <wrmeyer@immd3.informatik.uni-erlangen.de>
Date: Sat, 11 Nov 1995 20:22:22 +0100 (MET)
Subject: Re: Hexen scripting language
>
> > Gosh, and I thought John had better things to do. Like writing
> > QuakeEd. So he can write a quake editor and an hexen editor at
> > the same time, while playing deathmatch half of the day?
> >
> > However, that confirms the impression that the hexen script language
> > may be real close to .QP, and that the intermediary form of .QP might
> > be that strange 'compiled' form of hexen behavior.
> >
> > Another reason for Luc to build a hexen script decompiler.
> >
>
> Nope. HexenEd is an extension of DoomEd, which i wrote. Chris Rhinehart and
> Ben Gokey wrote the extensions to it and created HereticEd, then extended it
> more into HexenEd (all versions are NEXTSTEP only). John Carmack and I
> created QuakeEd which has nothing to do with our previous editors. I also
> don't deathmatch 1/2 the day -- i'm making Quake all day! I'm the Lead
> Designer!
If you have access to all those tools, why did you ask for third party
editors? Missing features like auto-align-textures, consistency check, etc.?
Don't write mails, design! 8)
Bye, Walter
P.S. Did you know that, according to one of our games mags, Carmack has left
ID Software to found a new company called Crack Dot Com, where he is
currently working on a game called Abuse?
- --
email: wrmeyer@cip.informatik.uni-erlangen.de
------------------------------
From: joost schuur <jschuur@jalad.globalnews.com>
Date: Sat, 11 Nov 1995 21:18:44 +0000 (GMT)
Subject: Re: Hexen scripting language
On Sat, 11 Nov 1995, Walter Meyer wrote:
> P.S. Did you know that, according to one of our games mags, Carmack has left
> ID Software to found a new company called Crack Dot Com, where he is
> currently working on a game called Abuse?
not true. dave taylor is funding the company of some friends called
'crack dot com'. they previosly released a cross platform paint programm
called 'satan paint' and just recently a platform game called 'abuse'.
(see http://www.crack.com).
neither dave nor john c left id.
</j>
------------------------------
From: Robert Forsman <thoth@cis.ufl.edu>
Date: Sat, 11 Nov 1995 15:33:24 EST
Subject: Re: Hexen scripting language
Walter Meyer <wrmeyer@immd3.informatik.uni-erlangen.de> ,in message <1995111119
22.UAA18474@faui30v.immd3.informatik.uni-erlangen.de>, wrote:
> P.S. Did you know that, according to one of our games mags, Carmack has lef
>> t
> ID Software to found a new company called Crack Dot Com, where he is
> currently working on a game called Abuse?
I've seen the game. The snareware is distributed in the Y section of
Slackware 3.0. You're this guy who looks like a Predator and you fight
critters that look like Aliens, but have guns and rockets. It's a side-view
hop and shoot. It's cute, but I've spent too much money on hardware
recently.
------------------------------
From: jbrown@odont.com (Morphius)
Date: 11 Nov 1995 15:57:28 PDT
Subject: Quake Scripting Language
What happened?!?! (i know this is off subject) Why isn't Quake making
Christmas?!?! Is it because you forgot to work on it or something?!?!
Since it ain't making Christmas gamers are going to expect a lot more
from it so it better be good.
------------------------------
End of doom-editing-digest V1 #478
**********************************