ZDCode [2.13.0] - The high-level DECORATE wrapper

Any utility that assists in the creation of mods, assets, etc, go here. For example: Ultimate Doom Builder, Slade, WadSmoosh, Oblige, etc.
Forum rules
The Projects forums are ONLY for YOUR PROJECTS! If you are asking questions about a project, either find that project's thread, or start a thread in the General section instead.

Got a cool project idea but nothing else? Put it in the project ideas thread instead!

Projects for any Doom-based engine (especially 3DGE) are perfectly acceptable here too.

Please read the full rules for more details.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

ZDCode [2.13.0] - The high-level DECORATE wrapper

Post by Gustavo6046 »

ZDCode

Take this example:

Code: Select all

class<Fatness, WalkDelay> ZombieGuy extends ZombieMan replaces ZombieMan {
    set Radius to Fatness;
    set XScale to Fatness;

    label See {
        x WalkDelay POSS A 1 A_Chase;
        inject FatWalk;
        x WalkDelay POSS B 1 A_Chase;
        inject FatWalk;
        x WalkDelay POSS C 1 A_Chase;
        inject FatWalk;
        x WalkDelay POSS D 1 A_Chase;
        inject FatWalk;

        Loop;
    };

    abstract macro FatWalk;
}

derive ZombieGuy::(80, 7) {
    macro FatWalk {};
} as FatZombie;

derive ZombieGuy::(20, 2) {
    macro FatWalk {
        if (z == floorz) sometimes 70 TNT1 A 0 ThrustThingZ(0, 12, 0, 1);
    };
} as ThinZombie;
This is what happens when that beauty goes through ZDCode II:

Code: Select all

Actor FatZombie : ZombieMan replaces ZombieMan
{
    Radius 80
    XScale 80
    States {
        See:
            POSS A 1 A_Chase
            POSS A 1 A_Chase
            POSS A 1 A_Chase
            POSS A 1 A_Chase
            POSS A 1 A_Chase
            POSS A 1 A_Chase
            POSS A 1 A_Chase
            POSS B 1 A_Chase
            POSS B 1 A_Chase
            POSS B 1 A_Chase
            POSS B 1 A_Chase
            POSS B 1 A_Chase
            POSS B 1 A_Chase
            POSS B 1 A_Chase
            POSS C 1 A_Chase
            POSS C 1 A_Chase
            POSS C 1 A_Chase
            POSS C 1 A_Chase
            POSS C 1 A_Chase
            POSS C 1 A_Chase
            POSS C 1 A_Chase
            POSS D 1 A_Chase
            POSS D 1 A_Chase
            POSS D 1 A_Chase
            POSS D 1 A_Chase
            POSS D 1 A_Chase
            POSS D 1 A_Chase
            POSS D 1 A_Chase
            loop
    }
}


Actor ThinZombie : ZombieMan replaces ZombieMan
{
    Radius 20
    XScale 20
    States {
        See:
            POSS A 1 A_Chase
            POSS A 1 A_Chase
            TNT1 A 0 A_JumpIf(!(z == floorz), 4)
                TNT1 A 0 A_Jump(76, 2)
                TNT1 A 0 ThrustThingZ(0, 12, 0, 1)
                TNT1 A 0
            TNT1 A 0
            POSS B 1 A_Chase
            POSS B 1 A_Chase
            TNT1 A 0 A_JumpIf(!(z == floorz), 4)
                TNT1 A 0 A_Jump(76, 2)
                TNT1 A 0 ThrustThingZ(0, 12, 0, 1)
                TNT1 A 0
            TNT1 A 0
            POSS C 1 A_Chase
            POSS C 1 A_Chase
            TNT1 A 0 A_JumpIf(!(z == floorz), 4)
                TNT1 A 0 A_Jump(76, 2)
                TNT1 A 0 ThrustThingZ(0, 12, 0, 1)
                TNT1 A 0
            TNT1 A 0
            POSS D 1 A_Chase
            POSS D 1 A_Chase
            TNT1 A 0 A_JumpIf(!(z == floorz), 4)
                TNT1 A 0 A_Jump(76, 2)
                TNT1 A 0 ThrustThingZ(0, 12, 0, 1)
                TNT1 A 0
            TNT1 A 0
            loop
    }
}
Yes, I know – the output code is quite cryptic, but you're not meant to touch that!

Grab It!

The source code is on GitHub. It is advised to install it via Python and pip - it is cross-platform, but it is Python, and thus requires Python to be run. pip will install dependencies automatically. A proper GUI (to configure and execute project builds) is planned, alongside batteries-included Windows binaries.
Last edited by Gustavo6046 on Tue May 11, 2021 1:13 pm, edited 7 times in total.
User avatar
Nash
 
 
Posts: 17433
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia
Contact:

Re: ZDCode II: The language that compiles to DECORATE!

Post by Nash »

How is this better than just using ZScript, especially if one is programming-literate enough to learn ZDCode's syntax - wouldn't it be less hassle and more efficient for them to just do it directly in the engine with ZScript?
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II: The language that compiles to DECORATE!

Post by Gustavo6046 »

This programming language targets older versions of ZDoom and ZDoom-derived source ports like Zandronum, most of which don't support ZScript. Thus, it is advised to use ZDCode only as a compatible alternative to DECORATE, not as a more flexible one (even though it is still more powerful).
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II: The language that compiles to DECORATE!

Post by Gustavo6046 »

I've got to announce two cool new things:
User avatar
TDRR
Posts: 815
Joined: Sun Mar 11, 2018 4:15 pm
Operating System Version (Optional): Manjaro/Win 8.1
Graphics Processor: Intel (Modern GZDoom)
Location: Venezuela

Re: ZDCode II: The language that compiles to DECORATE!

Post by TDRR »

This is really cool, i got to say, but is there any manual for it? I don't even know how to install it, and much less what are the available commands.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II: The language that compiles to DECORATE!

Post by Gustavo6046 »

TDRR wrote:This is really cool, i got to say, but is there any manual for it? I don't even know how to install it, and much less what are the available commands.
A more comprehensive documentation is currently on the to-do list for the language. To install it, one may simply use the Releases area in the repository, and download the source code zip. Currently, due to cross-platforming errors in the distribution script, we are unable to provide Windows binaries, so you will have to install Python 3 and use ZDCode as a module.

To be able to use ZDCode as a module from anywhere, first you need to install it, which can be done using two simple commands (assuming you have Python 3 installed, that it is executed as 'python' on Windows, and that you also have Git installed):

Code: Select all

git clone https://github.com/Gustavo6046/ZDCode
python -m pip install .
Then, you can use it using the following invocation:

Code: Select all

python -m zdcode LotsOfCode.zdc LotsOfCode.dec
where LotsOfCode.zdc is the input ZDCode file, which will be compiled, and stored into a new file called LotsOfCode.dec. You may, of course, use other filenames instead of LotsOfCode, but that's just an example. We don't even require the extensions to be those, though I would say using zdc for ZDCode and dec for ZDoom DECORATE is a good standard to follow.

Honestly, I wish I had written this in JavaScript, so it would be usable from the Web, and it would, as a bonus, be runnable offline using NodeJS.
User avatar
TDRR
Posts: 815
Joined: Sun Mar 11, 2018 4:15 pm
Operating System Version (Optional): Manjaro/Win 8.1
Graphics Processor: Intel (Modern GZDoom)
Location: Venezuela

Re: ZDCode II: The language that compiles to DECORATE!

Post by TDRR »

Nice, got it installed. It would be really cool if Zandronum adopted this language as a natively accepted one, maybe in a ZDCODE lump that would be parsed similar to a DECORATE one?
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II: The language that compiles to DECORATE!

Post by Gustavo6046 »

TDRR wrote:Nice, got it installed. It would be really cool if Zandronum adopted this language as a natively accepted one, maybe in a ZDCODE lump that would be parsed similar to a DECORATE one?
Well, ZDCode isn't very different from DECORATE, it merely compiles to DECORATE. I don't think that would be necessary, unless maybe when including the original ZDCode source code, or when making the compilation process automatic. Additionally, the standard ZDCode compiler is in Python, while the vast majority of source ports are in C or C++.

Also, you can import other ZDCode definitions using preprocessor directives, e.g.:

Code: Select all

#INCLUDE Filename_Without_Spaces.zdc
Currently imported scripts can't import other scripts, and you can not import filenames with spaces, but a new version is on the works, with a much better preprocessor, and a few issues corrected.

It is not possible to compile ZDCode lumps within WADs, PK3s, or any other archive/container format yet. It is necessary to have them as separate files in the filesystem.
User avatar
Enjay
 
 
Posts: 26517
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: ZDCode II: The language that compiles to DECORATE!

Post by Enjay »

Please forgive me for being obtuse here but, a bit like Nash wondering about what this offers versus ZSCRIPT, I'm actually wondering what it offers versus DECORATE. As far as I can see, it takes one set of text format, mostly human readable code (the ZDCode input) and converts it to another set of text format, mostly human readable code (i.e. the DECORATE output).

I'm obviously missing something here, but why is it better to code in ZDCode and compile it into DECORATE instead of just writing DECORATE code directly?
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II: The language that compiles to DECORATE!

Post by Gustavo6046 »

Enjay wrote:I'm obviously missing something here, but why is it better to code in ZDCode and compile it into DECORATE instead of just writing DECORATE code directly?
With ZDCode, you can use a special set of blocks (like while, if, etc), and even functions, that make the code more readable and organized. They might not be very powerful (functions don't accept parameters, because compatible DECORATE doesn't know scope or even local variables), but they are a great improvement in terms of how the code looks. It can also be very useful, for example, when repeating the same state a large amount of times (using the repeat block, aka 'x'), or when waiting for a simple condition (e.g. 'while ( z > floorz )' to repeat a state (or block of) until the actor lands).

Additionally, the shiny new preprocessor, that was just today added to the GitHub repository, allows for powerful macro replacement, conditional inclusion (or exclusion) of codes centered around preprocessor definitions, and even the (recursive) inclusion of multiple ZDCode files into a single DECORATE file, along with error messages that are easier to understand and use.

Let's say we have an offending line:

Code: Select all

#DEFINE ANNOYING

class RunZombie inherits ZombieMan replaces ZombieMan #2055
{
    set Gravity to 0.4; // high up...
    set Speed to 0;
    is NOBLOCKMONST;
    set Speed to 0;

    Thanos snapped this code.
 
    label See {}
}
Which is obviously the line that doesn't follow the language's syntax.

If we try to compile this file with the latest version of ZDCode, the error message is sound and clear:

Code: Select all

Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "zdcode/__main__.py", line 13, in <module>
    dec = zdcode.ZDCode.parse(open(sys.argv[1]).read(), os.path.dirname(sys.argv[1])).decorate()
  File "zdcode/__init__.py", line 518, in parse
    data = zdlexer.parse_code(code.strip(' \t\n'), dirname=dirname)
  File "zdcode/zdlexer.py", line 474, in parse_code
    return parse_postcode(preprocess_code(code, this_fname=filename, rel_dir=dirname))
  File "zdcode/zdlexer.py", line 471, in parse_postcode
    raise ZDParseError(m[1], postcode[int(m[2])])
zdlexer.ZDParseError: expected one of "'set' keyword", "isn't", '+', '-', '\\s+', 'combo', 'function ', 'is', 'label', 'method ', 'state', '}' at line 10 in "examples/JumpZombie.zc2"
>     Thanos snapped this code.
Of course, there is a traceback above, but always focus in the last few lines:

Code: Select all

zdlexer.ZDParseError: expected one of "'set' keyword", "isn't", '+', '-', '\\s+', 'combo', 'function ', 'is', 'label', 'method ', 'state', '}' at line 10 in "examples/JumpZombie.zc2"
>     Thanos snapped this code.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49056
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZDCode II: The language that compiles to DECORATE!

Post by Graf Zahl »

Gustavo6046 wrote: If we try to compile this file with the latest version of ZDCode, the error message is sound and clear:

Code: Select all

Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "zdcode/__main__.py", line 13, in <module>
    dec = zdcode.ZDCode.parse(open(sys.argv[1]).read(), os.path.dirname(sys.argv[1])).decorate()
  File "zdcode/__init__.py", line 518, in parse
    data = zdlexer.parse_code(code.strip(' \t\n'), dirname=dirname)
  File "zdcode/zdlexer.py", line 474, in parse_code
    return parse_postcode(preprocess_code(code, this_fname=filename, rel_dir=dirname))
  File "zdcode/zdlexer.py", line 471, in parse_postcode
    raise ZDParseError(m[1], postcode[int(m[2])])
zdlexer.ZDParseError: expected one of "'set' keyword", "isn't", '+', '-', '\\s+', 'combo', 'function ', 'is', 'label', 'method ', 'state', '}' at line 10 in "examples/JumpZombie.zc2"
>     Thanos snapped this code.
Sound and clear - yeah, right. I'd call that a lot of useless clutter that obstructs the real problem in a wall of text any normal person will have problems following through.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II: The language that compiles to DECORATE!

Post by Gustavo6046 »

Graf Zahl wrote:any normal person will have problems following through.
Well, I'm still looking for a way to eliminate the traceback. I guess I could print instead of raising an exception.

I just pushed to Git a commit that removes the ugly and unnecessary Python traceback from ZDCode parser errors.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II: The language that compiles to DECORATE!

Post by Gustavo6046 »

So I decided to revisit ZDCode, this time to add anonymous classes!

They're basically syntax sugar so you can quickly define a class you want to use, and that you know you will only use once. E.g. a RandomSpawner you define in the spot for A_SpawnItemEx:

Code: Select all

class AaaSpawner {
    label Spawn {
        TNT1 A 35;
        TNT1 A 0 A_SpawnItemEx(class extends TeleportFog {
            set Translation to "Ice";
        });
        TNT1 A 0 A_SpawnItemEx(class extends RandomSpawner {
            set DropItem to "ChaingunGuy", 128, 22;
            set DropItem to "Revenant", 200, 6;
            set DropItem to "ArchVile", 255, 1;
        });
        Loop;
    }
}
Unfortunately I am not able to update the VS Code plugin in the Marketplace. I will see what I can do about that.
But the new ZDCode compiler version should be up now.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

I added macro functions! Instead of creating internal DECORATE labels (like regular functions) to reuse code, they have their states added directly to inject statements that reference them. This might be a bit more efficient, at the cost of output size if there are many calls to a non-small macro.

See example below.

Code: Select all

class AaaSpawner {
    is NOGRAVITY;

    macro SpawnEither(A, B, C) {
        TNT1 A 0 A_SpawnItemEx(class extends TeleportFog {
            set Translation to "Ice";
        });
        TNT1 A 0 A_SpawnItemEx(class extends RandomSpawner {
            set DropItem to A, 128, 22;
            set DropItem to B, 200, 6;
            set DropItem to C, 255, 1;
        });
    };

    label Spawn {
        TNT1 A 35;

        x 3 {
            sometimes 60 inject SpawnEither("ChaingunGuy", "Revenant", "ArchVile");
            sometimes 60 inject SpawnEither("ChaingunGuy", "Revenant", "PainElemental");
        };

        Loop;
    };
}
User avatar
CBM
Posts: 373
Joined: Wed Oct 09, 2019 3:39 am
Graphics Processor: nVidia with Vulkan support
Location: The Shores of Hell

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by CBM »

looks interesting, it would be cool if it included a GUI editor with codecompletion and syntax highlighting as well as a complete reference to the language and code examples

anything in zcode II that will make generation of actors based soly on frame information very easy?
I am considering adding support for actor definitions to my md2modeldef tool
Post Reply

Return to “Creation, Conversion, and Editing”